diff --git a/MemberNodes.py b/MemberNodes.py
index 5571bbc4f83ee72f9598a8073125ce757ae4ea86..759f7216c3969debdb76d204ba6357ff57020530 100644
--- a/MemberNodes.py
+++ b/MemberNodes.py
@@ -77,6 +77,8 @@ class MethodNode(ASTNode):
 
         if self.body: self.children.append(self.body)
 
+    def __eq__(self, other):
+        return self.name == other.name and self.paramTypes == other.paramTypes
 
     def buildEnv(self, parentEnv):
         env = Env(parentEnv)
diff --git a/TypeNodes.py b/TypeNodes.py
index 2af75cf24e5245ff016dcbd521a7d8dae331e9b9..fb22369e534fb6c4aec8f27a952fce629faf1985 100644
--- a/TypeNodes.py
+++ b/TypeNodes.py
@@ -63,8 +63,6 @@ class ClassNode(ASTNode):
 
     def linkType(self):
         # link types to the actual nodes fom the environment (envs already created)
-        # to use: self.env.getNode(name, namespace)
-        # print('hello here we go we are in classNode {}'.format(self.name))
         if self.env is not None:
             if self.superClass:
                 newSuperClass = self.env.getNode(self.superClass, 'type')
@@ -77,28 +75,66 @@ class ClassNode(ASTNode):
     def checkHierarchy(self):
         if self.superClass:
             # A class must not extend an interface.
-            if isinstance(self.superClass, InterNode):
+            if not isinstance(self.superClass, ClassNode):
                 raise Exception("ERROR: Class {} extends interface {}".format(self.name, self.superClass.name))
             # A class must not extend a final class.
             if 'final' in self.superClass.mods:
                 raise Exception("ERROR: Class {} extends final class {}".format(self.name, self.superClass.name))
-        # A class must not implement a class.
+        # A class must not implement a class. No duplicate interfaces.
         if self.superInter:
+            unique = []
             for inter in self.superInter:
-                if isinstance(inter, ClassNode):
+                if not isinstance(inter, InterNode):
                     raise Exception("ERROR: Class {} implements class {}".format(self.name, inter.name))
+                if inter.name in unique:
+                    raise Exception("ERROR: Class {} implements duplicate interfaces {}".format(self.name, inter.name))
+                unique.append(inter.name)
         
         # A class or interface must not declare two methods with the same signature (name and parameter types).
-        uniqueMethods = []
+        unique = []
         for method in self.methods:
             key = (method.name, method.paramTypes)
-            if key in uniqueMethods:
+            if key in unique:
                 raise Exception("ERROR: Class {} declares 2 methods with the same signature {}".format(self.name, key[0]))
-            uniqueMethods.append(key)
-        # A class or interface must not contain (declare or inherit) two methods with the same signature but different return types
+            unique.append(key)
+
         # A class must not declare two constructors with the same parameter types
+        unique = []
+        for cons in self.constructors:
+            key = (cons.name, cons.paramTypes)
+            if key in unique:
+                raise Exception("ERROR: Class {} declares 2 constructors with the same parameter types".format(self.name))
+            unique.append(key)
         
+        # A class or interface must not contain (declare or inherit) two methods with the same signature but different return types
+        # The hierarchy must be acyclic
+        contains = self.getContains([])
         # A class that contains (declares or inherits) any abstract methods must be abstract.
+        for con in contains:
+            if 'abstract' in con.mods and 'abstract' not in self.mods:
+                raise Exception("ERROR: Non-abstract Class {} contains an abstract method".format(self.name))
+
+    # hierarchy: string[]
+    def getContains(self, hierarchy):
+        # check if not acyclic
+        if self.name in hierarchy:
+            raise Exception("ERROR: The hierarchy is not acyclic {}".format(hierarchy))
+        hierarchy.append(self.name)
+        # get contains
+        contains = self.methods
+        if self.superClass:
+            superContains = self.superClass.getContains(hierarchy)
+            for con in superContains:
+                conOverwritten = False
+                for method in self.methods:
+                    if (method == con):
+                        if (method.methodType != con.methodType):
+                            raise Exception("ERROR: Class {} contains 2 methods {} with the same signature but different return types".format(self.name, method.name))
+                        conOverwritten = True
+                        break
+                if not conOverwritten:
+                    contains.append(con)
+        return contains
 
     def getConstructor(self, argTypes):
         for c in self.constructors:
@@ -147,3 +183,6 @@ class InterNode(ASTNode):
                 for (index, inter) in enumerate(self.superInter):
                     newSuperInter = self.env.getNode(inter, 'type')
                     self.superInter[index] = newSuperInter
+
+    def checkHierarchy(self):
+        pass
diff --git a/UnitNodes.py b/UnitNodes.py
index 65bd3c61c8c7c29f9274c4599b22b18725d616ca..476423887f6838e0279a85c938ce82ea1feb45f3 100644
--- a/UnitNodes.py
+++ b/UnitNodes.py
@@ -69,3 +69,6 @@ class TypeNode(ASTNode):
             nameNodes = getParseTreeNodes(['LSQRBRACK'], parseTree)
             if nameNodes:
                 self.isArray = True
+
+    def __eq__(self, other):
+        return self.name == other.name
\ No newline at end of file