diff --git a/src/main/jastadd/Analysis.jrag b/src/main/jastadd/Analysis.jrag
index 0524c6175805427457e5918b5eb6e1b330608768..27f3a7d89731f351b8a21043e9b2a816cd3d3548 100644
--- a/src/main/jastadd/Analysis.jrag
+++ b/src/main/jastadd/Analysis.jrag
@@ -4,95 +4,105 @@ import java.util.*;
 aspect TypeAnalysis {
   public abstract TypeUse Component.getTypeUse();
 
+  //--- lookupType ---
   syn TypeDecl TypeUse.decl() = lookupType(getID());
   inh TypeDecl TypeUse.lookupType(String name);
+  inh TypeDecl TypeDecl.lookupType(String name);
   eq Program.getChild().lookupType(String name) {
-    for (TypeDecl td: getTypeDecls()) {
+    for (TypeDecl td : getTypeDecls()) {
       if (td.getID().equals(name)) {
         return td;
       }
     }
     return null;
   }
-  syn boolean TypeDecl.isAlreadyDeclared()
-    = lookupType(getID()) != this;
-  inh TypeDecl TypeDecl.lookupType(String name);
 
-  syn TypeDecl TypeDecl.mostGeneralSuperType() {
-    if (!hasSuper()) {
-      return this;
-    } else {
-      return getSuper().decl().mostGeneralSuperType();
-    }
-  }
+  //--- isAlreadyDeclared ---
+  syn boolean TypeDecl.isAlreadyDeclared() = lookupType(getID()) != this;
 }
 
 aspect ComponentAnalysis {
-  syn boolean Component.isTargetOfDirectedRelation() = false;
-  eq RelationComponent.isTargetOfDirectedRelation() = isTargetOfRightDirection() | isTargetOfLeftDirection();
-  inh boolean RelationComponent.isTargetOfRightDirection();
-  eq Relation.getRight().isTargetOfRightDirection()
-    = getDirection() instanceof RightDirection;
-  eq Program.getChild().isTargetOfRightDirection() = false;
-  inh boolean RelationComponent.isTargetOfLeftDirection();
-  eq Relation.getLeft().isTargetOfLeftDirection()
-    = getDirection() instanceof LeftDirection;
-  eq Program.getChild().isTargetOfLeftDirection() = false;
+  //--- isTargetOfDirectedRelation ---
+  inh boolean Component.isTargetOfDirectedRelation();
+  eq Relation.getRight().isTargetOfDirectedRelation() = getDirection() instanceof RightDirection;
+  eq Program.getChild().isTargetOfDirectedRelation() = false;
 
+  //--- name ---
   syn String Component.name() = getID();
 
-  syn TypeDecl Component.toTypeDecl() = enclosingTypeDecl();
-  eq RelationComponent.toTypeDecl() = getTypeUse().decl();
+  //--- enclosingTypeDecl ---
   inh TypeDecl Component.enclosingTypeDecl();
   eq TypeDecl.getChild().enclosingTypeDecl() = this;
   eq Program.getChild().enclosingTypeDecl() = null;
 
+  //--- otherSide ---
   inh RelationComponent RelationComponent.otherSide();
   eq Relation.getLeft().otherSide() = getRight();
   eq Relation.getRight().otherSide() = getLeft();
   eq Program.getChild().otherSide() = null;
 
-  syn TypeDecl RelationComponent.ofTypeDecl() = otherSide().toTypeDecl();
+  //--- ofTypeDecl ---
+  syn TypeDecl RelationComponent.ofTypeDecl() = otherSide().getTypeUse().decl();
 
-  syn boolean Component.isAlreadyDeclared()
-    = !isTargetOfDirectedRelation()
-      && toTypeDecl() != null
-      && lookupComponent(toTypeDecl(), name()) != this;
-  inh Component Component.lookupComponent(TypeDecl td, String name);
-  eq Program.getChild().lookupComponent(TypeDecl td, String name)
-    = lookupComponentSyn(td, name);
-  syn Component Program.lookupComponentSyn(TypeDecl td, String name) {
+  //--- isAlreadyDeclared ---
+  /**
+   * Check, if role with the same name is already declared on the same nonterminal
+   */
+  syn boolean RelationComponent.isAlreadyDeclared()
+    = !isTargetOfDirectedRelation()                     /* if unnamed in relation, there is no role name, so no error */
+      && getTypeUse().decl() != null                           /* nonterminal type of role is defined */
+      && findComponent(getTypeUse().decl(), name()) != this;   /* there is another role defined previously with the same name */
+
+  //--- findComponent ---
+  /** Search for either a component on the RHS of the given type with the given name,
+   *   or a relation part for the given type and a role with the given name */
+  inh Component Component.findComponent(TypeDecl td, String name);
+  eq Program.getChild().findComponent(TypeDecl td, String name)
+    = findComponentSyn(td, name);
+  syn Component Program.findComponentSyn(TypeDecl td, String name) {
     for (Component c: td.getComponents()) {
       if (c.name().equals(name)) {
         return c;
       }
     }
 
-    for (Relation r: getRelations()) {
-      Component c = r.getLeft().lookup(td, name);
-      if (c != null) return c;
-      c = r.getRight().lookup(td, name);
-      if (c != null) return c;
+    for (Relation r : getRelations()) {
+      if (r.getLeft().matches(td, name))
+        return r.getLeft();
+      if (r.getRight().matches(td, name))
+        return r.getRight();
     }
 
     return null;
   }
 
-  syn boolean Component.isInvalidRedefinition() {
-    if (toTypeDecl() == null) return false;
+  //--- isInvalidRedefinition ---
+  /**
+   * Check, if a component with the same name is already declared in some supertype
+   */
+  syn boolean Component.isInvalidRedefinition() = invalidRedefinition() != null;
 
-    TypeDecl td = toTypeDecl();
+  /**
+   * Check, if a component with the same name is already declared in some supertype, and return it, if any
+   */
+  syn Component Component.invalidRedefinition() = null;
+  eq TokenComponent.invalidRedefinition() = invalidRedefinitionOn(enclosingTypeDecl());
+  eq RelationComponent.invalidRedefinition() = invalidRedefinitionOn(getTypeUse().decl());
+
+  syn Component Component.invalidRedefinitionOn(TypeDecl td) {
+    if (td == null) return null;
 
     while (td.hasSuper() && td.getSuper().decl() != null) {
       td = td.getSuper().decl();
-      Component c = lookupComponent(td, getID());
-      if (c != null && isTargetOfDirectedRelation()) return true;
+      // find a matching component on the RHS of the (current) super type
+      Component c = findComponent(td, getID());
 
-      if (c != null && !this.isEqual(c)) return true;
+      if (c != null && !this.isEqual(c)) return c;
     }
-    return false;
+    return null;
   }
 
+  //--- isEqual ---
   syn boolean Component.isEqual(Component c) = this.getClass() == c.getClass() && getTypeUse().isEqual(c.getTypeUse());
 
   syn boolean TypeUse.isEqual(TypeUse u);
@@ -108,20 +118,23 @@ aspect ComponentAnalysis {
     return true;
   }
 
-  syn RelationComponent RelationComponent.lookup(TypeDecl td, String name)
-    = !isTargetOfDirectedRelation() && toTypeDecl() == td && name().equals(name)
-    ? this
-    : null;
-
+  //--- matches ---
+  /**
+   * @return true, if the component has both type and role, its type matches the given typeDecl and its name matches the given name
+   */
+  syn boolean RelationComponent.matches(TypeDecl td, String name)
+    = !isTargetOfDirectedRelation() && getTypeUse().decl() == td && name().equals(name);
 
+  //--- relationComponents ---
   coll Set<RelationComponent> TypeDecl.relationComponents()
     [new HashSet<RelationComponent>()]
     root Program;
   RelationComponent contributes this
-    when !isTargetOfDirectedRelation() && toTypeDecl() != null
+    when !isTargetOfDirectedRelation() && getTypeUse().decl() != null
     to TypeDecl.relationComponents()
-    for toTypeDecl();
+    for getTypeUse().decl();
 
+  //--- relationComponentsTransitive ---
   syn Collection<RelationComponent> TypeDecl.relationComponentsTransitive() {
     ArrayList<RelationComponent> list = new ArrayList<>();
     if (hasSuper() && getSuper().decl() != null) {
@@ -131,6 +144,7 @@ aspect ComponentAnalysis {
     return list;
   }
 
+  //--- oneRelationComponents ---
   syn Set<OneRelationComponent> TypeDecl.oneRelationComponents() {
     Set<OneRelationComponent> set = new HashSet<>();
     for (RelationComponent rc: relationComponents()) {
@@ -141,27 +155,33 @@ aspect ComponentAnalysis {
     return set;
   }
 
+  //--- needUnresolvedClass ---
   syn boolean TypeDecl.needUnresolvedClass() {
     // a TypeDecl needs an unresolved class, if it can appear in a relation
     // TODO
     return true;
   }
 
+  //--- isList ---
   syn boolean Component.isList() = false;
   eq ListComponent.isList() = true;
 
+  //--- isOpt ---
   syn boolean Component.isOpt() = false;
   eq OptComponent.isOpt() = true;
 
+  //--- isNullable ---
   syn boolean Component.isNullable() = false;
   eq TokenComponent.isNullable() = !"float double int short long char byte boolean".contains(getTypeUse().getID());
 }
 
 aspect InstanceSupplier {
 
+  //--- program ---
   inh Program TypeDecl.program();
   eq Program.getTypeDecl(int i).program() = this;
 
+  //--- subTypeDecls ---
   syn Collection<TypeDecl> TypeDecl.subTypeDecls() {
     java.util.List<TypeDecl> subDecls = new ArrayList();
     for (TypeDecl decl : program().getTypeDeclList()) {
@@ -172,6 +192,7 @@ aspect InstanceSupplier {
     return subDecls;
   }
 
+  //--- instantiableSubType ---
   syn TypeDecl TypeDecl.instantiableSubType() {
     if (getAbstract() == false) {
       return this;
@@ -192,6 +213,7 @@ aspect InstanceSupplier {
 }
 
 aspect Constructors {
+  //--- componentsTransitive ---
   syn Collection<Component> TypeDecl.componentsTransitive() {
     ArrayList<Component> list = new ArrayList<>();
     if (hasSuper() && getSuper().decl() != null) {
@@ -205,6 +227,7 @@ aspect Constructors {
     return list;
   }
 
+  //--- needsConstructor ---
   syn boolean TypeDecl.needsConstructor() {
     if (componentsTransitive().isEmpty()) {
       return false;
@@ -217,30 +240,37 @@ aspect Constructors {
       && getSuper().decl().needsConstructor();
   }
 
+  //--- inConstructor ---
   /**
    * @return true, if the component should be added to the constructor (i.e., is not an NTA)
    */
   syn boolean Component.inConstructor() = true;
   eq NTAComponent.inConstructor() = false;
+  eq NTAOptComponent.inConstructor() = false;
+  eq NTAListComponent.inConstructor() = false;
 }
 
 aspect Utils {
 
+  //--- isMany ---
   syn boolean RelationComponent.isMany() = false;
   eq ManyRelationComponent.isMany() = true;
 
+  //--- toString ---
   public String SimpleTypeUse.toString() {
     return getID();
   }
   public String ParameterizedTypeUse.toString() {
     StringBuilder sb = new StringBuilder();
     sb.append(getID()).append("<");
-    int i = 0;
+    boolean first = true;
     for (TypeUse u: getTypeUses()) {
-      sb.append(u.toString());
-      if (++i < getNumTypeUse()) {
+      if (first) {
+        first = false;
+      } else {
         sb.append(", ");
       }
+      sb.append(u.toString());
     }
     sb.append(">");
     return sb.toString();
diff --git a/src/main/jastadd/Backend.jadd b/src/main/jastadd/Backend.jadd
index f5d69d3facd57a19d3d5630d339455b928ddcc68..a3711d389ad5f5d1423fd8a1df97e900588306a8 100644
--- a/src/main/jastadd/Backend.jadd
+++ b/src/main/jastadd/Backend.jadd
@@ -240,7 +240,7 @@ aspect BackendDirectedAPI {
     generateGetOne(sb);
 
     // Set
-    sb.append(ind(1) + "public " + toTypeDecl() + " " + toTypeDecl());
+    sb.append(ind(1) + "public " + getTypeUse().decl() + " " + getTypeUse().decl());
     sb.append(".set" + nameCapitalized() + "(" + ofTypeDecl() + " o) {\n");
     if (!optional) {
       sb.append(ind(2) + "assertNotNull(o);\n");
@@ -252,7 +252,7 @@ aspect BackendDirectedAPI {
 
   public void ManyRelationComponent.generateDirectedAPI(StringBuilder sb) {
     // Get
-    sb.append(ind(1) + "public java.util.List<" + ofTypeDecl() + "> " + toTypeDecl() + ".");
+    sb.append(ind(1) + "public java.util.List<" + ofTypeDecl() + "> " + getTypeUse().decl() + ".");
     if (useJastAddNames) {
       // getXs
       sb.append("get" + nameCapitalized() + "s() {\n");
@@ -260,7 +260,7 @@ aspect BackendDirectedAPI {
       sb.append(ind(1) + "}\n");
 
       // getXList
-      sb.append(ind(1) + "public java.util.List<" + ofTypeDecl() + "> " + toTypeDecl());
+      sb.append(ind(1) + "public java.util.List<" + ofTypeDecl() + "> " + getTypeUse().decl());
       sb.append(".get" + nameCapitalized() + "List() {\n");
     } else {
       sb.append(name() + "() {\n");
@@ -287,7 +287,7 @@ aspect BackendDirectedAPI {
     sb.append(ind(1) + "}\n");
 
     // Add
-    sb.append(ind(1) + "public void " + toTypeDecl() + ".add");
+    sb.append(ind(1) + "public void " + getTypeUse().decl() + ".add");
     if (!useJastAddNames) {
       sb.append("To");
     }
@@ -302,7 +302,7 @@ aspect BackendDirectedAPI {
     sb.append(ind(1) + "}\n");
 
     // Insert / add at specific position
-    sb.append(ind(1) + "public void " + toTypeDecl() + ".add");
+    sb.append(ind(1) + "public void " + getTypeUse().decl() + ".add");
     if (!useJastAddNames) {
       sb.append("To");
     }
@@ -317,7 +317,7 @@ aspect BackendDirectedAPI {
     sb.append(ind(1) + "}\n");
 
     // Remove
-    sb.append(ind(1) + "public void " + toTypeDecl() + ".remove");
+    sb.append(ind(1) + "public void " + getTypeUse().decl() + ".remove");
     if (!useJastAddNames) {
       sb.append("From");
     }
@@ -331,7 +331,7 @@ aspect BackendDirectedAPI {
   }
 
   public void RelationComponent.generateGetOne(StringBuilder sb) {
-    sb.append(ind(1) + "public " + ofTypeDecl() + " " + toTypeDecl() + ".");
+    sb.append(ind(1) + "public " + ofTypeDecl() + " " + getTypeUse().decl() + ".");
     if (useJastAddNames) {
       sb.append("get" + nameCapitalized());
     } else {
@@ -353,7 +353,7 @@ aspect BackendDirectedAPI {
 
   public void RelationComponent.generateExtraOptAPI(StringBuilder sb) {
     // has
-    sb.append(ind(1) + "public boolean " + toTypeDecl());
+    sb.append(ind(1) + "public boolean " + getTypeUse().decl());
     sb.append(".has" + nameCapitalized() + "() {\n");
     sb.append(ind(2) + "return ");
     if (useJastAddNames) {
@@ -365,7 +365,7 @@ aspect BackendDirectedAPI {
     sb.append(ind(1) + "}\n");
 
     // clear
-    sb.append(ind(1) + "public void " + toTypeDecl());
+    sb.append(ind(1) + "public void " + getTypeUse().decl());
     sb.append(".clear" + nameCapitalized() + "() {\n");
     sb.append(ind(2) + "set" + nameCapitalized() + "(null);\n");
     sb.append(ind(1) + "}\n");
@@ -418,7 +418,7 @@ aspect BackendBidirectionalAPI {
     generateGetOne(sb);
 
     // Set
-    sb.append(ind(1) + "public " + toTypeDecl() + " " + toTypeDecl());
+    sb.append(ind(1) + "public " + getTypeUse().decl() + " " + getTypeUse().decl());
     sb.append(".set" + nameCapitalized() + "(" + ofTypeDecl() + " o) {\n");
     if (!isOpt) {
       sb.append(ind(2) + "assertNotNull(o);\n");
@@ -465,7 +465,7 @@ aspect BackendBidirectionalAPI {
 
   public void RelationComponent.generateBiManyMany(StringBuilder sb, RelationComponent opposite) {
     // Get
-    sb.append(ind(1) + "public java.util.List<" + ofTypeDecl() + "> " + toTypeDecl() + ".");
+    sb.append(ind(1) + "public java.util.List<" + ofTypeDecl() + "> " + getTypeUse().decl() + ".");
     if (useJastAddNames) {
       // getXs
       sb.append("get" + nameCapitalized() + "s() {\n");
@@ -473,7 +473,7 @@ aspect BackendBidirectionalAPI {
       sb.append(ind(1) + "}\n");
 
       // getXList
-      sb.append(ind(1) + "public java.util.List<" + ofTypeDecl() + "> " + toTypeDecl());
+      sb.append(ind(1) + "public java.util.List<" + ofTypeDecl() + "> " + getTypeUse().decl());
       sb.append(".get" + nameCapitalized() + "List() {\n");
     } else {
       sb.append(name() + "() {\n");
@@ -489,7 +489,7 @@ aspect BackendBidirectionalAPI {
             sb.append(ind(5) + "changed = true;\n");
             sb.append(ind(5) + ofTypeDecl() + " resolvedElement = resolve" + nameCapitalized() + "ByToken(element.as$Unresolved().getUnresolved$Token(), i);\n");
             sb.append(ind(5) + "if (resolvedElement != null && element.as$Unresolved().getUnresolved$ResolveOpposite()) {\n");
-              sb.append(ind(6) + ASTNode.listClass + "<" + toTypeDecl() + "> otherList = resolvedElement." + opposite.getImplAttributeField() + ";\n");
+              sb.append(ind(6) + ASTNode.listClass + "<" + getTypeUse().decl() + "> otherList = resolvedElement." + opposite.getImplAttributeField() + ";\n");
               sb.append(ind(6) + "if (otherList == null) {\n");
                 sb.append(ind(7) + "otherList = new " + listClass + "<>();\n");
               sb.append(ind(6) + "}\n");
@@ -508,7 +508,7 @@ aspect BackendBidirectionalAPI {
     sb.append(ind(1) + "}\n");
 
     // Add
-    sb.append(ind(1) + "public void " + toTypeDecl() + ".add");
+    sb.append(ind(1) + "public void " + getTypeUse().decl() + ".add");
     if (!useJastAddNames) {
       sb.append("To");
     }
@@ -529,7 +529,7 @@ aspect BackendBidirectionalAPI {
     sb.append(ind(1) + "}\n");
 
     // Insert / add at specific position
-    sb.append(ind(1) + "public void " + toTypeDecl() + ".add");
+    sb.append(ind(1) + "public void " + getTypeUse().decl() + ".add");
     if (!useJastAddNames) {
       sb.append("To");
     }
@@ -551,7 +551,7 @@ aspect BackendBidirectionalAPI {
     sb.append(ind(1) + "}\n");
 
     // Remove
-    sb.append(ind(1) + "public void " + toTypeDecl() + ".remove");
+    sb.append(ind(1) + "public void " + getTypeUse().decl() + ".remove");
     if (!useJastAddNames) {
       sb.append("From");
     }
@@ -571,7 +571,7 @@ aspect BackendBidirectionalAPI {
 
   public void RelationComponent.generateBiManyOne(StringBuilder sb, RelationComponent opposite) {
     // Get
-    sb.append(ind(1) + "public java.util.List<" + ofTypeDecl() + "> " + toTypeDecl() + ".");
+    sb.append(ind(1) + "public java.util.List<" + ofTypeDecl() + "> " + getTypeUse().decl() + ".");
     if (useJastAddNames) {
       // getXs
       sb.append("get" + nameCapitalized() + "s() {\n");
@@ -579,7 +579,7 @@ aspect BackendBidirectionalAPI {
       sb.append(ind(1) + "}\n");
 
       // getXList
-      sb.append(ind(1) + "public java.util.List<" + ofTypeDecl() + "> " + toTypeDecl());
+      sb.append(ind(1) + "public java.util.List<" + ofTypeDecl() + "> " + getTypeUse().decl());
       sb.append(".get" + nameCapitalized() + "List() {\n");
     } else {
       sb.append(name() + "() {\n");
@@ -595,7 +595,7 @@ aspect BackendBidirectionalAPI {
             sb.append(ind(5) + "changed = true;\n");
             sb.append(ind(5) + ofTypeDecl() + " resolvedElement = resolve" + nameCapitalized() + "ByToken(element.as$Unresolved().getUnresolved$Token(), i);\n");
             sb.append(ind(5) + "if (element.as$Unresolved().getUnresolved$ResolveOpposite()) {\n");
-              sb.append(ind(6) + toTypeDecl() + " oldTarget = resolvedElement." + opposite.getImplAttributeField() + ";\n");
+              sb.append(ind(6) + getTypeUse().decl() + " oldTarget = resolvedElement." + opposite.getImplAttributeField() + ";\n");
               sb.append(ind(6) + "if (oldTarget != null && oldTarget != this) {\n");
                 sb.append(ind(7) + "oldTarget." + getImplAttributeField() + ".remove(resolvedElement);\n");
               sb.append(ind(6) + "}\n");
@@ -620,7 +620,7 @@ aspect BackendBidirectionalAPI {
     sb.append(ind(1) + "}\n");
 
     // Add
-    sb.append(ind(1) + "public void " + toTypeDecl() + ".add");
+    sb.append(ind(1) + "public void " + getTypeUse().decl() + ".add");
     if (!useJastAddNames) {
       sb.append("To");
     }
@@ -643,7 +643,7 @@ aspect BackendBidirectionalAPI {
     sb.append(ind(1) + "}\n");
 
     // Insert / add at specific position
-    sb.append(ind(1) + "public void " + toTypeDecl() + ".add");
+    sb.append(ind(1) + "public void " + getTypeUse().decl() + ".add");
     if (!useJastAddNames) {
       sb.append("To");
     }
@@ -664,7 +664,7 @@ aspect BackendBidirectionalAPI {
     sb.append(ind(1) + "}\n");
 
     // Remove
-    sb.append(ind(1) + "public void " + toTypeDecl() + ".remove");
+    sb.append(ind(1) + "public void " + getTypeUse().decl() + ".remove");
     if (!useJastAddNames) {
       sb.append("From");
     }
@@ -685,13 +685,13 @@ aspect BackendBidirectionalAPI {
     generateGetOne(sb);
 
     // Set
-    sb.append(ind(1) + "public " + toTypeDecl() + " " + toTypeDecl() + ".set" + nameCapitalized()
+    sb.append(ind(1) + "public " + getTypeUse().decl() + " " + getTypeUse().decl() + ".set" + nameCapitalized()
       + "(" + ofTypeDecl() + " o) {\n");
     if (!isOpt) {
       sb.append(ind(2) + "assertNotNull(o);\n");
     }
     sb.append(ind(2) + "if (" + getImplAttributeField() + " != null) {\n");
-    sb.append(ind(3) + ASTNode.listClass + "<" + toTypeDecl() + "> list2 = " + getImplAttributeField()
+    sb.append(ind(3) + ASTNode.listClass + "<" + getTypeUse().decl() + "> list2 = " + getImplAttributeField()
       + "." + otherSide().getImplAttributeField() + ";\n");
     sb.append(ind(3) + "list2.remove(this);\n");
     sb.append(ind(3) + getImplAttributeField() + "." + "set"
@@ -703,7 +703,7 @@ aspect BackendBidirectionalAPI {
     if (isOpt) {
       sb.append(ind(2) + "if (o != null) {\n");
     }
-    sb.append(ind(ind) + ASTNode.listClass + "<" + toTypeDecl() + "> list = o."
+    sb.append(ind(ind) + ASTNode.listClass + "<" + getTypeUse().decl() + "> list = o."
       + otherSide().getImplAttributeField() + ";\n");
     sb.append(ind(ind) + "if (list == null) {\n");
     sb.append(ind(ind+1) + "list = new " + ASTNode.listClass + "<>();\n");
@@ -933,13 +933,13 @@ aspect NameResolutionHelper {
   public void ManyRelationComponent.generateContextDependentNameResolution(StringBuilder sb) {
 
     if (serializer && !resolverHelper) {
-      sb.append(ind(1) + ofTypeDecl() + " " + toTypeDecl() + ".resolve" + nameCapitalized() + "ByToken(String id, int position) {\n");
+      sb.append(ind(1) + ofTypeDecl() + " " + getTypeUse().decl() + ".resolve" + nameCapitalized() + "ByToken(String id, int position) {\n");
         sb.append(ind(2) + "return (" + ofTypeDecl() + ") globallyResolveASTNodeByUID(id);\n");
       sb.append(ind(1) + "}\n");
     } else {
       sb.append(ind(1) + "// context-dependent name resolution\n");
-      sb.append(ind(1) + "uncache " + toTypeDecl() + ".resolve" + nameCapitalized() + "ByToken(String id, int position);\n");
-      sb.append(ind(1) + "syn " + ofTypeDecl() + " " + toTypeDecl() + ".resolve" + nameCapitalized() + "ByToken(String id, int position) {\n");
+      sb.append(ind(1) + "uncache " + getTypeUse().decl() + ".resolve" + nameCapitalized() + "ByToken(String id, int position);\n");
+      sb.append(ind(1) + "syn " + ofTypeDecl() + " " + getTypeUse().decl() + ".resolve" + nameCapitalized() + "ByToken(String id, int position) {\n");
         sb.append(ind(2) + "// default to context-independent name resolution\n");
         sb.append(ind(2) + "return globallyResolve" + ofTypeDecl() + "ByToken(id);\n");
       sb.append(ind(1) + "}\n");
@@ -948,13 +948,13 @@ aspect NameResolutionHelper {
 
   public void RelationComponent.generateDirectedContextDependentNameResolution(StringBuilder sb) {
     if (serializer && !resolverHelper) {
-      sb.append(ind(1) + ofTypeDecl() + " " + toTypeDecl() + ".resolve" + nameCapitalized() + "ByToken(String id) {\n");
+      sb.append(ind(1) + ofTypeDecl() + " " + getTypeUse().decl() + ".resolve" + nameCapitalized() + "ByToken(String id) {\n");
         sb.append(ind(2) + "return (" + ofTypeDecl() + ") globallyResolveASTNodeByUID(id);\n");
       sb.append(ind(1) + "}\n");
     } else {
       sb.append(ind(1) + "// context-dependent name resolution\n");
-      sb.append(ind(1) + "uncache " + toTypeDecl() + ".resolve" + nameCapitalized() + "ByToken(String id);\n");
-      sb.append(ind(1) + "syn " + ofTypeDecl() + " " + toTypeDecl() + ".resolve" + nameCapitalized() + "ByToken(String id) {\n");
+      sb.append(ind(1) + "uncache " + getTypeUse().decl() + ".resolve" + nameCapitalized() + "ByToken(String id);\n");
+      sb.append(ind(1) + "syn " + ofTypeDecl() + " " + getTypeUse().decl() + ".resolve" + nameCapitalized() + "ByToken(String id) {\n");
         sb.append(ind(2) + "// default to context-independent name resolution\n");
         sb.append(ind(2) + "return globallyResolve" + ofTypeDecl() + "ByToken(id);\n");
       sb.append(ind(1) + "}\n");
diff --git a/src/main/jastadd/Errors.jrag b/src/main/jastadd/Errors.jrag
index 9d9f75505aa01df342dd6b9e365c091b4a7ce6c7..b1ec073575e4ea6c15e924c1f6c6b95eeaba2cba 100644
--- a/src/main/jastadd/Errors.jrag
+++ b/src/main/jastadd/Errors.jrag
@@ -15,18 +15,25 @@ aspect Errors {
     when isAlreadyDeclared()
     to Program.errors();
 
-  Component contributes error("Component '" + name()
-      + "' is already declared for type '" + toTypeDecl() + "'")
+  RelationComponent contributes error("Role '" + name()
+      + "' is already declared for type '" + getTypeUse().decl() + "'")
     when isAlreadyDeclared()
     to Program.errors();
 
-  Component contributes error("Component '" + name()
-    + "' is an invalid redefition for type '" + toTypeDecl() + "'")
+  RelationComponent contributes error("Role '" + name()
+    + "' is an invalid redefinition for type '" + getTypeUse().decl() + "', conflicts with supertype '"
+    + invalidRedefinition().enclosingTypeDecl() + "'")
+    when isInvalidRedefinition()
+    to Program.errors();
+
+  TokenComponent contributes error("Token '" + name()
+    + "' is an invalid redefinition for type '" + enclosingTypeDecl() + "', conflicts with supertype '"
+    + invalidRedefinition().enclosingTypeDecl() + "'")
     when isInvalidRedefinition()
     to Program.errors();
 
   RelationComponent contributes
-    error("Role name missing for type '" + toTypeDecl() + "'")
+    error("Role name missing for type '" + getTypeUse().decl() + "'")
     when !isTargetOfDirectedRelation() && name().isEmpty()
     to Program.errors();
 
diff --git a/src/main/jastadd/RelAst.parser b/src/main/jastadd/RelAst.parser
index 303dcb6dd727df10b4037d110e234213fdc90b36..6b138b97d35b76583a3226b376613b8316a95a36 100644
--- a/src/main/jastadd/RelAst.parser
+++ b/src/main/jastadd/RelAst.parser
@@ -86,9 +86,15 @@ Relation relation =
   RELATION relation_comp.l direction relation_comp.r SCOL
    {:
       Relation result = new Relation();
-      result.setLeft(l);
-      result.setDirection(direction);
-      result.setRight(r);
+      if (direction instanceof LeftDirection) {
+        result.setLeft(r);
+        result.setDirection(new RightDirection());
+        result.setRight(l);
+      } else {
+        result.setLeft(l);
+        result.setDirection(direction);
+        result.setRight(r);
+      }
       return result;
    :}
   ;
diff --git a/src/test/jastadd/errors/Errors.expected b/src/test/jastadd/errors/Errors.expected
index 01049a4a3ae266a25ed024698f93ad49b129aab2..be149e0fda289a2a4d5203d5bb6317b0a0a73434 100644
--- a/src/test/jastadd/errors/Errors.expected
+++ b/src/test/jastadd/errors/Errors.expected
@@ -3,3 +3,4 @@ $FILENAME Line 5, column 5: Role name missing for type 'A'
 $FILENAME Line 6, column 15: Role name missing for type 'B'
 $FILENAME Line 7, column 12: The target of a directed relation cannot have a role name
 $FILENAME Line 8, column 13: The target of a directed relation may only have multiplicity 1
+$FILENAME Line 9, column 5: Role 'b2' is already declared for type 'A'
diff --git a/src/test/jastadd/errors/Errors.relast b/src/test/jastadd/errors/Errors.relast
index c5bfd75f87b2ff697a558f0491211025d23e4ddc..1d63f5705ecc09ac2e431dbbfbb26a850a466825 100644
--- a/src/test/jastadd/errors/Errors.relast
+++ b/src/test/jastadd/errors/Errors.relast
@@ -6,3 +6,4 @@ rel A -> B;
 rel A.bs* <-> B*;
 rel A.b -> B.b;
 rel A.b2 -> B*;
+rel A.b2 -> A;
diff --git a/src/test/jastadd/errors/ErrorsLeft.expected b/src/test/jastadd/errors/ErrorsLeft.expected
index 155d0ec5110a4f6156e71033e92137a6aebb0492..191db3e226f8e5cb2cf64059954fdeee57f2d94b 100644
--- a/src/test/jastadd/errors/ErrorsLeft.expected
+++ b/src/test/jastadd/errors/ErrorsLeft.expected
@@ -3,3 +3,4 @@ $FILENAME Line 5, column 10: Role name missing for type 'A'
 $FILENAME Line 6, column 15: Role name missing for type 'B'
 $FILENAME Line 7, column 5: The target of a directed relation cannot have a role name
 $FILENAME Line 8, column 5: The target of a directed relation may only have multiplicity 1
+$FILENAME Line 9, column 10: Role 'b2' is already declared for type 'A'
diff --git a/src/test/jastadd/errors/ErrorsLeft.relast b/src/test/jastadd/errors/ErrorsLeft.relast
index e381449c06b7f0223b36b8b0936f417c5811bb7b..5c4c35abe374c258b732989d9ef7dfacca051ce9 100644
--- a/src/test/jastadd/errors/ErrorsLeft.relast
+++ b/src/test/jastadd/errors/ErrorsLeft.relast
@@ -6,3 +6,4 @@ rel B <- A;
 rel A.bs* <-> B*;
 rel B.b <- A.b;
 rel B* <- A.b2;
+rel A <- A.b2;
diff --git a/src/test/jastadd/errors/Inheritance.expected b/src/test/jastadd/errors/Inheritance.expected
index 717389a4052a506dbe52c3734c9880b7f5c709fe..b3382e004ae6e15ca9bbd1ed6695ece0e3110fbe 100644
--- a/src/test/jastadd/errors/Inheritance.expected
+++ b/src/test/jastadd/errors/Inheritance.expected
@@ -1,3 +1,3 @@
 Errors:
-$FILENAME Line 4, column 12: Component 'X' is an invalid redefition for type 'B3'
-$FILENAME Line 7, column 5: Component 'X' is an invalid redefition for type 'B2'
+$FILENAME Line 4, column 12: Token 'X' is an invalid redefinition for type 'B3', conflicts with supertype 'A'
+$FILENAME Line 7, column 5: Role 'X' is an invalid redefinition for type 'B2', conflicts with supertype 'A'
diff --git a/src/test/jastadd/errors/InheritanceLeft.expected b/src/test/jastadd/errors/InheritanceLeft.expected
index 2cb8024867b5c38771a337330d2e87a8035be653..a897e473946be908e3cac5f6b6d59628720d3376 100644
--- a/src/test/jastadd/errors/InheritanceLeft.expected
+++ b/src/test/jastadd/errors/InheritanceLeft.expected
@@ -1,3 +1,3 @@
 Errors:
-$FILENAME Line 4, column 12: Component 'X' is an invalid redefition for type 'B3'
-$FILENAME Line 7, column 10: Component 'X' is an invalid redefition for type 'B2'
+$FILENAME Line 4, column 12: Token 'X' is an invalid redefinition for type 'B3', conflicts with supertype 'A'
+$FILENAME Line 7, column 10: Role 'X' is an invalid redefinition for type 'B2', conflicts with supertype 'A'