diff --git a/alib2data/src/graph/directed/AdjacencyMatrixDirectedGraph.cpp b/alib2data/src/graph/directed/AdjacencyMatrixDirectedGraph.cpp
index e27b23436719e0a894375be1f197cc8b2f700a55..6bcdb3dc426f2884ec45e69253a1c98aa22a4cb9 100644
--- a/alib2data/src/graph/directed/AdjacencyMatrixDirectedGraph.cpp
+++ b/alib2data/src/graph/directed/AdjacencyMatrixDirectedGraph.cpp
@@ -51,7 +51,7 @@ std::set<Node> AdjacencyMatrixDirectedGraph::neighbors(const Node &node) const
 	}
 
 	for (auto i : search->second) {
-		if (i.second) {
+		if (i.second > 0) {
 			out.insert(i.first);
 		}
 	}
@@ -115,7 +115,7 @@ bool AdjacencyMatrixDirectedGraph::addEdge(const DirectedEdge &edge)
 
 	edges.insert(edge);
 
-	adj[edge.getFromNode()].insert({edge.getToNode(), true});
+	adj[edge.getFromNode()][edge.getToNode()]++;
 
 	return true;
 }
@@ -129,9 +129,9 @@ bool AdjacencyMatrixDirectedGraph::removeEdge(const DirectedEdge &edge)
 
 	edges.erase(search);
 
-	// Don't touch adj if there still is an edge, in case of multigraph
-	if (findEdges(edge.getFromNode(), edge.getToNode()).empty()) {
-		auto &map = adj[edge.getFromNode()];
+	auto &map = adj[edge.getFromNode()];
+	int &val = map[edge.getToNode()];
+	if (--val <= 0) {
 		map.erase(edge.getToNode());
 		if (map.empty()) {
 			adj.erase(edge.getFromNode());
diff --git a/alib2data/src/graph/directed/AdjacencyMatrixDirectedGraph.h b/alib2data/src/graph/directed/AdjacencyMatrixDirectedGraph.h
index a3f9915d0c3ed89ece71e7825be4df297a056f43..5dc9aa4adce0a08d65bcc78f90ae8fa342f3549b 100644
--- a/alib2data/src/graph/directed/AdjacencyMatrixDirectedGraph.h
+++ b/alib2data/src/graph/directed/AdjacencyMatrixDirectedGraph.h
@@ -14,18 +14,17 @@ namespace graph {
  *
  *  unordered_map:
  *    [ -- ][ n1 ][ n2 ][ n3 ][ n4 ]
- *    [ n1 ]  -     x     -     x
- *    [ n2 ]  x     -     -     x
- *    [ n3 ]  -     -     -     x
- *    [ n4 ]  x     -     x     -
+ *    [ n1 ]  0     2     0     1
+ *    [ n2 ]  1     0     0     1
+ *    [ n3 ]  0     0     0     1
+ *    [ n4 ]  1     0     1     0
  *
  *  edges:
- *    n1 -> n2, n1 -> n4
+ *    n1 -> n2, n1 -> n2, n1 -> n4
  *    n2 -> n1, n2 -> n4
  *    n3 -> n4
  *    n4 -> n1, n4 -> n3
  *
- *  multi-edges are stored in edges std::set
  */
 
 class AdjacencyMatrixDirectedGraph : public IDirectedGraph
@@ -51,7 +50,7 @@ public:
 
 private:
 	std::set<DirectedEdge> edges;
-	std::unordered_map<Node, std::unordered_map<Node, bool>> adj;
+	std::unordered_map<Node, std::unordered_map<Node, int>> adj;
 };
 
 } // namespace graph
diff --git a/alib2data/src/graph/undirected/AdjacencyMatrixUndirectedGraph.cpp b/alib2data/src/graph/undirected/AdjacencyMatrixUndirectedGraph.cpp
index bba341d080b283557a0412f332d2a5e2cccb89ee..49c50ba2e3977dd1e32d10721d728264685d4801 100644
--- a/alib2data/src/graph/undirected/AdjacencyMatrixUndirectedGraph.cpp
+++ b/alib2data/src/graph/undirected/AdjacencyMatrixUndirectedGraph.cpp
@@ -52,7 +52,7 @@ std::set<Node> AdjacencyMatrixUndirectedGraph::neighbors(const Node &node) const
 	}
 
 	for (auto i : search->second) {
-		if (i.second) {
+		if (i.second > 0) {
 			out.insert(i.first);
 		}
 	}
@@ -117,8 +117,8 @@ bool AdjacencyMatrixUndirectedGraph::addEdge(const UndirectedEdge &edge)
 
 	edges.insert(edge);
 
-	adj[edge.getFirstNode()].insert({edge.getSecondNode(), true});
-	adj[edge.getSecondNode()].insert({edge.getFirstNode(), true});
+	adj[edge.getFirstNode()][edge.getSecondNode()]++;
+	adj[edge.getSecondNode()][edge.getFirstNode()]++;
 
 	return true;
 }
@@ -132,15 +132,18 @@ bool AdjacencyMatrixUndirectedGraph::removeEdge(const UndirectedEdge &edge)
 
 	edges.erase(search);
 
-	// Don't touch adj if there still is an edge, in case of multigraph
-	if (findEdges(edge.getFirstNode(), edge.getSecondNode()).empty()) {
-		auto &map1 = adj[edge.getFirstNode()];
+	auto &map1 = adj[edge.getFirstNode()];
+	int &val1 = map1[edge.getSecondNode()];
+	if (--val1 <= 0) {
 		map1.erase(edge.getSecondNode());
 		if (map1.empty()) {
 			adj.erase(edge.getFirstNode());
 		}
+	}
 
-		auto &map2 = adj[edge.getSecondNode()];
+	auto &map2 = adj[edge.getSecondNode()];
+	int &val2 = map2[edge.getFirstNode()];
+	if (--val2 <= 0) {
 		map2.erase(edge.getFirstNode());
 		if (map2.empty()) {
 			adj.erase(edge.getSecondNode());
diff --git a/alib2data/src/graph/undirected/AdjacencyMatrixUndirectedGraph.h b/alib2data/src/graph/undirected/AdjacencyMatrixUndirectedGraph.h
index 337d875d8b798550795de3231616b5b75df975c1..a877b030ab61ed92dbd946618f3ffb77a9989017 100644
--- a/alib2data/src/graph/undirected/AdjacencyMatrixUndirectedGraph.h
+++ b/alib2data/src/graph/undirected/AdjacencyMatrixUndirectedGraph.h
@@ -14,20 +14,19 @@ namespace graph {
  *
  *  unordered_map:
  *    [ -- ][ n1 ][ n2 ][ n3 ][ n4 ]
- *    [ n1 ]  -     x     x     x
- *    [ n2 ]  x     -     -     x
- *    [ n3 ]  x     -     -     x
- *    [ n4 ]  x     x     x     -
+ *    [ n1 ]  0     2     1     1
+ *    [ n2 ]  2     0     0     1
+ *    [ n3 ]  1     0     0     1
+ *    [ n4 ]  1     1     1     0
  *
  *  edges:
- *    n1 <-> n2, n1 <-> n3, n1 <-> n4
+ *    n1 <-> n2, n1 <-> n2, n1 <-> n3, n1 <-> n4
  *    n2 <-> n4
  *    n3 <-> n4
  *
  *  undirected edge n1 <-> n2 is represented as
  *  directed edge n1 -> n2 and directed edge n2 -> n1
  *
- *  multi-edges are stored in edges std::set
  */
 
 class AdjacencyMatrixUndirectedGraph : public IUndirectedGraph
@@ -53,7 +52,7 @@ public:
 
 private:
 	std::set<UndirectedEdge> edges;
-	std::unordered_map<Node, std::unordered_map<Node, bool>> adj;
+	std::unordered_map<Node, std::unordered_map<Node, int>> adj;
 };
 
 } // namespace graph
diff --git a/alib2data/test-src/graph/GraphTest.cpp b/alib2data/test-src/graph/GraphTest.cpp
index f9f33a3e10d51072ef837931b33639543d203caa..9ae3f19f625d60e9e4721bffa6cb244de8304e91 100644
--- a/alib2data/test-src/graph/GraphTest.cpp
+++ b/alib2data/test-src/graph/GraphTest.cpp
@@ -329,22 +329,23 @@ void GraphTest::testRemoveEdge_impl(graph::REPRESENTATION representation)
 	graph::DirectedGraph dg(representation);
 	dg.addEdge(graph::DirectedEdge(n1, n2));
 	dg.addEdge(graph::DirectedEdge(n1, n2, "multi-edge"));
+	dg.addEdge(graph::DirectedEdge(n1, n3));
 	dg.addEdge(graph::DirectedEdge(n2, n3));
 	dg.addEdge(graph::DirectedEdge(n3, n4));
 	dg.addEdge(graph::DirectedEdge(n4, n1));
 
 	CPPUNIT_ASSERT_EQUAL_INT(4, dg.getNodes().size());
-	CPPUNIT_ASSERT_EQUAL_INT(5, dg.getEdges().size());
+	CPPUNIT_ASSERT_EQUAL_INT(6, dg.getEdges().size());
 
-	CPPUNIT_ASSERT_EQUAL_INT(1, dg.neighbors(n1).size());
+	CPPUNIT_ASSERT_EQUAL_INT(2, dg.neighbors(n1).size());
 	dg.removeEdge(graph::DirectedEdge(n1, n2));
 	CPPUNIT_ASSERT_EQUAL_INT(1, dg.findEdges(n1, n2).size());
-	CPPUNIT_ASSERT_EQUAL_INT(1, dg.neighbors(n1).size());
+	CPPUNIT_ASSERT_EQUAL_INT(2, dg.neighbors(n1).size());
 
-	CPPUNIT_ASSERT_EQUAL_INT(1, dg.neighbors(n1).size());
+	CPPUNIT_ASSERT_EQUAL_INT(2, dg.neighbors(n1).size());
 	dg.removeEdge(graph::DirectedEdge(n1, n2, "multi-edge"));
 	CPPUNIT_ASSERT_EQUAL_INT(0, dg.findEdges(n1, n2).size());
-	CPPUNIT_ASSERT_EQUAL(true, dg.neighbors(n1).empty());
+	CPPUNIT_ASSERT_EQUAL_INT(1, dg.neighbors(n1).size());
 
 	CPPUNIT_ASSERT_EQUAL_INT(1, dg.neighbors(n2).size());
 	dg.removeEdge(graph::DirectedEdge(n2, n3));
@@ -361,6 +362,11 @@ void GraphTest::testRemoveEdge_impl(graph::REPRESENTATION representation)
 	CPPUNIT_ASSERT_EQUAL_INT(0, dg.findEdges(n4, n1).size());
 	CPPUNIT_ASSERT_EQUAL(true, dg.neighbors(n4).empty());
 
+	CPPUNIT_ASSERT_EQUAL_INT(1, dg.neighbors(n1).size());
+	dg.removeEdge(graph::DirectedEdge(n1, n3));
+	CPPUNIT_ASSERT_EQUAL_INT(0, dg.findEdges(n1, n3).size());
+	CPPUNIT_ASSERT_EQUAL(true, dg.neighbors(n1).empty());
+
 	CPPUNIT_ASSERT_EQUAL(true, dg.getEdges().empty());
 	CPPUNIT_ASSERT_EQUAL(true, dg.getNodes().empty());