diff --git a/src/main/jastadd/backend/API.jadd b/src/main/jastadd/backend/API.jadd
index 9476a471da1954e02347d4c216fb2c45df47bc89..dc7ba525c65d4c79f1a952d07f978f157ed48fe3 100644
--- a/src/main/jastadd/backend/API.jadd
+++ b/src/main/jastadd/backend/API.jadd
@@ -15,11 +15,15 @@ aspect BackendAPI {
   public void RelationComponent.generateAPI(StringBuilder sb) {
     if (otherSide().isNavigable()) {
       if (multiplicityOne() || multiplicityOpt()) {
+        generateGetOne(sb);
         if (otherSide().multiplicityOne() || otherSide().multiplicityOpt()) {
           generateBiOneOne(sb);
         } else if (otherSide().multiplicityMany()) {
           generateBiOneMany(sb);
         }
+        if (isOpt()) {
+          generateExtraOptAPI(sb);
+        }
       } else if (multiplicityMany()) {
         if (otherSide().multiplicityOne() || otherSide().multiplicityOpt()) {
           generateBiManyOne(sb);
@@ -29,13 +33,38 @@ aspect BackendAPI {
       }
     } else {
       if (multiplicityOne() || multiplicityOpt()) {
+        generateGetOne(sb);
         generateDirectedZeroOneAPI(sb);
+        if (isOpt()) {
+          generateExtraOptAPI(sb);
+        }
       } else if (multiplicityMany()) {
         generateDirectedManyAPI(sb);
       }
     }
   }
 
+  public void RelationComponent.generateGetOne(StringBuilder sb) {
+    sb.append(ind(1) + "public " + ofTypeDecl() + " " + getTypeUse().decl() + ".");
+    if (useJastAddNames) {
+      sb.append("get" + nameCapitalized());
+    } else {
+      sb.append(name());
+    }
+    sb.append("() {\n");
+    if (resolverHelper | serializer) {
+      sb.append(ind(2) + "if (" + getImplAttributeField() + " != null && " + getImplAttributeField() + ".is$Unresolved()) {\n");
+        sb.append(ind(3) + "if (" + getImplAttributeField() + ".as$Unresolved().getUnresolved$ResolveOpposite()) {\n");
+          sb.append(ind(4) + "set" + nameCapitalized() + "(resolve" + nameCapitalized() + "ByToken(" + getImplAttributeField() + ".as$Unresolved().getUnresolved$Token()));\n");
+        sb.append(ind(3) + "} else {\n");
+          sb.append(ind(4) + "set" + getImplAttributeName() + "(resolve" + nameCapitalized() + "ByToken(" + getImplAttributeField() + ".as$Unresolved().getUnresolved$Token()));\n");
+        sb.append(ind(3) + "}\n");
+      sb.append(ind(2) + "}\n");
+    }
+    sb.append(ind(2) + "return get" + getImplAttributeName() + "();\n");
+    sb.append(ind(1) + "}\n");
+  }
+
   public void RelationComponent.generateExtraOptAPI(StringBuilder sb) {
     // has
     sb.append(ind(1) + "public boolean " + getTypeUse().decl());
diff --git a/src/main/jastadd/backend/BidirectionalAPI.jadd b/src/main/jastadd/backend/BidirectionalAPI.jadd
index 205668357ada568344130746cc1d8a798cab6369..fa2688a655699e4fec6facc5fe0303bcd397f66a 100644
--- a/src/main/jastadd/backend/BidirectionalAPI.jadd
+++ b/src/main/jastadd/backend/BidirectionalAPI.jadd
@@ -1,53 +1,31 @@
 aspect BackendBidirectionalAPI {
 
   public void RelationComponent.generateBiOneOne(StringBuilder sb) {
-    // Get
-    generateGetOne(sb);
+    boolean resolve = resolverHelper || serializer;
 
     // Set
-    sb.append(ind(1) + "public " + getTypeUse().decl() + " " + getTypeUse().decl());
-    sb.append(".set" + nameCapitalized() + "(" + ofTypeDecl() + " o) {\n");
+    sb.append(ind(1) + "public " + getTypeUse().decl() + " " + getTypeUse().decl() + ".set" + nameCapitalized() + "(" + ofTypeDecl() + " o) {\n");
     if (!isOpt()) {
       sb.append(ind(2) + "assertNotNull(o);\n");
     }
     // unset the old opposite
-    sb.append(ind(2) + "if (" + getImplAttributeField() + " != null) {\n");
-    sb.append(ind(3) + "" + getImplAttributeField() + ".set" + otherSide().getImplAttributeName() + "(null);\n");
-    sb.append(ind(2) + "}\n");
-    if (resolverHelper | serializer) {
-      sb.append(ind(2) + "if (o != null && !o.is$Unresolved() && o." + otherSide().getImplAttributeField() + " != null) {\n");
-    } else {
-      sb.append(ind(2) + "if (o != null && o." + otherSide().getImplAttributeField() + " != null) {\n");
-    }
+    sb.append(ind(2) + "if (" + getImplAttributeField() + " != null)\n");
+    sb.append(ind(3) + getImplAttributeField() + ".set" + otherSide().getImplAttributeName() + "(null);\n");
+
+    sb.append(ind(2) + "if (o != null && " + (resolve ? "!o." + isUnresolvedMethod + "() && o." : "o.") + otherSide().getImplAttributeField() + " != null) {\n");
     sb.append(ind(3) + "o." + otherSide().getImplAttributeField() + ".set" + getImplAttributeName() + "(null);\n");
     sb.append(ind(2) + "}\n");
     sb.append(ind(2) + "set" + getImplAttributeName() + "(o);\n");
-    if (resolverHelper | serializer) {
-      sb.append(ind(2) + "if (o == null || !o.is$Unresolved()) {\n");
-      if (isOpt()) {
-        sb.append(ind(3) + "if (o != null) {\n");
-        sb.append(ind(4) + "o.set" + otherSide().getImplAttributeName() + "(this);\n");
-        sb.append(ind(3) + "}\n");
-      } else {
-        sb.append(ind(3) + "o.set" + otherSide().getImplAttributeName() + "(this);\n");
-      }
-      sb.append(ind(2) + "}\n");
-    } else {
-      if (isOpt()) {
-        sb.append(ind(2) + "if (o != null) {\n");
-        sb.append(ind(3) + "o.set" + otherSide().getImplAttributeName() + "(this);\n");
-        sb.append(ind(2) + "}\n");
-      } else {
-        sb.append(ind(2) + "o.set" + otherSide().getImplAttributeName() + "(this);\n");
-      }
+    if (resolve) {
+      sb.append(ind(2) + "if (o == null || !o." + isUnresolvedMethod + "())\n");
     }
+    if (isOpt()) {
+      sb.append(ind(resolve ? 3 : 2) + "if (o != null)\n");
+    }
+    sb.append(ind((isOpt() ? 1 : 0) + (resolve ? 3 : 2)) + "o.set" + otherSide().getImplAttributeName() + "(this);\n");
 
     sb.append(ind(2) + "return this;\n");
     sb.append(ind(1) + "}\n");
-
-    if (isOpt()) {
-      generateExtraOptAPI(sb);
-    }
   }
 
   public void RelationComponent.generateBiManyMany(StringBuilder sb) {
@@ -69,37 +47,33 @@ aspect BackendBidirectionalAPI {
     // resolve the entire list
     if (resolverHelper | serializer) {
       sb.append(ind(2) + "if (l != null) {\n");
-        sb.append(ind(3) + "boolean changed = false;\n");
-        sb.append(ind(3) + "for (int i = 0; i < l.size(); i++) {\n");
-          sb.append(ind(4) + ofTypeDecl() + " element = l.get(i);\n");
-          sb.append(ind(4) + "if (element.is$Unresolved()) {\n");
-            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 + "<" + getTypeUse().decl() + "> otherList = resolvedElement." + otherSide().getImplAttributeField() + ";\n");
-              sb.append(ind(6) + "if (otherList == null) {\n");
-                sb.append(ind(7) + "otherList = new " + listClass + "<>();\n");
-              sb.append(ind(6) + "}\n");
-              sb.append(ind(6) + "otherList.add(this);\n");
-              sb.append(ind(6) + "resolvedElement.set" + otherSide().getImplAttributeName() + "(otherList);\n");
-            sb.append(ind(5) + "}\n");
-            sb.append(ind(5) + "l.set(i, resolvedElement);\n");
-          sb.append(ind(4) + "}\n");
-        sb.append(ind(3) + "}\n");
-        sb.append(ind(3) + "if (changed) {\n");
-          sb.append(ind(4) + "set" + getImplAttributeName() + "(l);\n");
-        sb.append(ind(3) + "}\n");
+      sb.append(ind(3) + "boolean changed = false;\n");
+      sb.append(ind(3) + "for (int i = 0; i < l.size(); i++) {\n");
+      sb.append(ind(4) + ofTypeDecl() + " element = l.get(i);\n");
+      sb.append(ind(4) + "if (element." + isUnresolvedMethod + "()) {\n");
+      sb.append(ind(5) + "changed = true;\n");
+      sb.append(ind(5) + ofTypeDecl() + " resolvedElement = resolve" + nameCapitalized() + "ByToken(element." + asUnresolvedMethod + "()." + getUnresolvedTokenMethod + "(), i);\n");
+      sb.append(ind(5) + "if (resolvedElement != null && element." + asUnresolvedMethod + "()." + getUnresolvedResolveOppositeMethod + "()) {\n");
+      sb.append(ind(6) + ASTNode.listClass + "<" + getTypeUse().decl() + "> otherList = resolvedElement." + otherSide().getImplAttributeField() + ";\n");
+      sb.append(ind(6) + "if (otherList == null) {\n");
+      sb.append(ind(7) + "otherList = new " + listClass + "<>();\n");
+      sb.append(ind(6) + "}\n");
+      sb.append(ind(6) + "otherList.add(this);\n");
+      sb.append(ind(6) + "resolvedElement.set" + otherSide().getImplAttributeName() + "(otherList);\n");
+      sb.append(ind(5) + "}\n");
+      sb.append(ind(5) + "l.set(i, resolvedElement);\n");
+      sb.append(ind(4) + "}\n");
+      sb.append(ind(3) + "}\n");
+      sb.append(ind(3) + "if (changed) {\n");
+      sb.append(ind(4) + "set" + getImplAttributeName() + "(l);\n");
+      sb.append(ind(3) + "}\n");
       sb.append(ind(2) + "}\n");
     }
     sb.append(ind(2) + "return l != null ? Collections.unmodifiableList(l) : Collections.emptyList();\n");
     sb.append(ind(1) + "}\n");
 
     // Add
-    sb.append(ind(1) + "public void " + getTypeUse().decl() + ".add");
-    if (!useJastAddNames) {
-      sb.append("To");
-    }
-    sb.append(nameCapitalized() + "(" + ofTypeDecl() + " o) {\n");
+    sb.append(ind(1) + "public void " + getTypeUse().decl() + ".add" + (useJastAddNames ? "" : "To") + nameCapitalized() + "(" + ofTypeDecl() + " o) {\n");
     sb.append(ind(2) + "assertNotNull(o);\n");
     sb.append(ind(2) + ASTNode.listClass + "<" + ofTypeDecl() + "> list = " + getImplAttributeField() + ";\n");
     sb.append(ind(2) + "if (list == null) {\n");
@@ -116,18 +90,13 @@ aspect BackendBidirectionalAPI {
     sb.append(ind(1) + "}\n");
 
     // Insert / add at specific position
-    sb.append(ind(1) + "public void " + getTypeUse().decl() + ".add");
-    if (!useJastAddNames) {
-      sb.append("To");
-    }
-    sb.append(nameCapitalized() + "(int index, " + ofTypeDecl() + " o) {\n");
+    sb.append(ind(1) + "public void " + getTypeUse().decl() + ".add" + (useJastAddNames ? "" : "To") + nameCapitalized() + "(int index, " + ofTypeDecl() + " o) {\n");
     sb.append(ind(2) + "assertNotNull(o);\n");
     sb.append(ind(2) + ASTNode.listClass + "<" + ofTypeDecl() + "> list = " + getImplAttributeField() + ";\n");
     sb.append(ind(2) + "if (list == null) {\n");
     sb.append(ind(3) + "list = new " + ASTNode.listClass + "<>();\n");
     sb.append(ind(2) + "}\n");
-    sb.append(ind(2) + ASTNode.listClass + "<" + otherSide().ofTypeDecl() + "> list2 = o."
-    + otherSide().getImplAttributeField() + ";\n");
+    sb.append(ind(2) + ASTNode.listClass + "<" + otherSide().ofTypeDecl() + "> list2 = o." + otherSide().getImplAttributeField() + ";\n");
     sb.append(ind(2) + "if (list2 == null) {\n");
     sb.append(ind(3) + "list2 = new "+ ASTNode.listClass + "<>();\n");
     sb.append(ind(2) + "}\n");
@@ -138,16 +107,11 @@ aspect BackendBidirectionalAPI {
     sb.append(ind(1) + "}\n");
 
     // Remove
-    sb.append(ind(1) + "public void " + getTypeUse().decl() + ".remove");
-    if (!useJastAddNames) {
-      sb.append("From");
-    }
-    sb.append(nameCapitalized() + "(" + ofTypeDecl() + " o) {\n");
+    sb.append(ind(1) + "public void " + getTypeUse().decl() + ".remove" + (useJastAddNames ? "" : "From") + nameCapitalized() + "(" + ofTypeDecl() + " o) {\n");
     sb.append(ind(2) + "assertNotNull(o);\n");
     sb.append(ind(2) + ASTNode.listClass + "<" + ofTypeDecl() + "> list = " + getImplAttributeField() + ";\n");
     sb.append(ind(2) + "if (list != null && list.remove(o)) {\n");
-    sb.append(ind(3) + ASTNode.listClass + "<" + otherSide().ofTypeDecl() + "> list2 = o."
-      + otherSide().getImplAttributeField() + ";\n");
+    sb.append(ind(3) + ASTNode.listClass + "<" + otherSide().ofTypeDecl() + "> list2 = o." + otherSide().getImplAttributeField() + ";\n");
     sb.append(ind(3) + "if (list2 != null) list2.remove(this);\n");
     sb.append(ind(3) + "set" + getImplAttributeName() + "(list);\n");
     sb.append(ind(3) + "o.set" + otherSide().getImplAttributeName() + "(list2);\n");
@@ -175,50 +139,44 @@ aspect BackendBidirectionalAPI {
     // resolve the entire list
     if (resolverHelper | serializer) {
       sb.append(ind(2) + "if (l != null) {\n");
-        sb.append(ind(3) + "boolean changed = false;\n");
-        sb.append(ind(3) + "for (int i = 0; i < l.size(); i++) {\n");
-          sb.append(ind(4) + ofTypeDecl() + " element = l.get(i);\n");
-          sb.append(ind(4) + "if (element.is$Unresolved()) {\n");
-            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) + getTypeUse().decl() + " oldTarget = resolvedElement." + otherSide().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");
-              sb.append(ind(6) + "if (oldTarget == this) {\n");
-                sb.append(ind(7) + "l.remove(i);\n");
-                sb.append(ind(7) + "i--;\n");
-              sb.append(ind(6) + "} else {\n");
-                sb.append(ind(7) + "resolvedElement.set" + otherSide().getImplAttributeName() + "(this);\n");
-                sb.append(ind(7) + "l.set(i, resolvedElement);\n");
-              sb.append(ind(6) + "}\n");
-            sb.append(ind(5) + "} else {\n");
-              sb.append(ind(6) + "l.set(i, resolvedElement);\n");
-            sb.append(ind(5) + "}\n");
-          sb.append(ind(4) + "}\n");
-        sb.append(ind(3) + "}\n");
-        sb.append(ind(3) + "if (changed) {\n");
-          sb.append(ind(4) + "set" + getImplAttributeName() + "(l);\n");
-        sb.append(ind(3) + "}\n");
+      sb.append(ind(3) + "boolean changed = false;\n");
+      sb.append(ind(3) + "for (int i = 0; i < l.size(); i++) {\n");
+      sb.append(ind(4) + ofTypeDecl() + " element = l.get(i);\n");
+      sb.append(ind(4) + "if (element." + isUnresolvedMethod + "()) {\n");
+      sb.append(ind(5) + "changed = true;\n");
+      sb.append(ind(5) + ofTypeDecl() + " resolvedElement = resolve" + nameCapitalized() + globallyResolvePostfix + "(element." + asUnresolvedMethod + "()." + getUnresolvedTokenMethod + "(), i);\n");
+      sb.append(ind(5) + "if (element." + asUnresolvedMethod + "()." + getUnresolvedResolveOppositeMethod + "()) {\n");
+      sb.append(ind(6) + getTypeUse().decl() + " oldTarget = resolvedElement." + otherSide().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");
+      sb.append(ind(6) + "if (oldTarget == this) {\n");
+      sb.append(ind(7) + "l.remove(i);\n");
+      sb.append(ind(7) + "i--;\n");
+      sb.append(ind(6) + "} else {\n");
+      sb.append(ind(7) + "resolvedElement.set" + otherSide().getImplAttributeName() + "(this);\n");
+      sb.append(ind(7) + "l.set(i, resolvedElement);\n");
+      sb.append(ind(6) + "}\n");
+      sb.append(ind(5) + "} else {\n");
+      sb.append(ind(6) + "l.set(i, resolvedElement);\n");
+      sb.append(ind(5) + "}\n");
+      sb.append(ind(4) + "}\n");
+      sb.append(ind(3) + "}\n");
+      sb.append(ind(3) + "if (changed) {\n");
+      sb.append(ind(4) + "set" + getImplAttributeName() + "(l);\n");
+      sb.append(ind(3) + "}\n");
       sb.append(ind(2) + "}\n");
     }
     sb.append(ind(2) + "return l != null ? Collections.unmodifiableList(l) : Collections.emptyList();\n");
     sb.append(ind(1) + "}\n");
 
     // Add
-    sb.append(ind(1) + "public void " + getTypeUse().decl() + ".add");
-    if (!useJastAddNames) {
-      sb.append("To");
-    }
-    sb.append(nameCapitalized() + "(" + ofTypeDecl() + " o) {\n");
+    sb.append(ind(1) + "public void " + getTypeUse().decl() + ".add" + (useJastAddNames ? "" : "To") + nameCapitalized() + "(" + ofTypeDecl() + " o) {\n");
     sb.append(ind(2) + "assertNotNull(o);\n");
     sb.append(ind(2) + "if (o != null && o." + otherSide().getImplAttributeField() + " != null) {\n");
-    sb.append(ind(3) + ASTNode.listClass + "<" + ofTypeDecl() + "> list2 = o."
-      + otherSide().getImplAttributeField() + "." + getImplAttributeField() + ";\n");
+    sb.append(ind(3) + ASTNode.listClass + "<" + ofTypeDecl() + "> list2 = o." + otherSide().getImplAttributeField() + "." + getImplAttributeField() + ";\n");
     sb.append(ind(3) + "if (list2.remove(o))\n");
-    sb.append(ind(4) + "o." + otherSide().getImplAttributeField()
-      + ".set" + getImplAttributeName() + "(list2);\n");
+    sb.append(ind(4) + "o." + otherSide().getImplAttributeField()  + ".set" + getImplAttributeName() + "(list2);\n");
     sb.append(ind(2) + "}\n");
     sb.append(ind(2) + ASTNode.listClass + "<" + ofTypeDecl() + "> list = " + getImplAttributeField() + ";\n");
     sb.append(ind(2) + "if (list == null) {\n");
@@ -230,32 +188,24 @@ aspect BackendBidirectionalAPI {
     sb.append(ind(1) + "}\n");
 
     // Insert / add at specific position
-    sb.append(ind(1) + "public void " + getTypeUse().decl() + ".add");
-    if (!useJastAddNames) {
-      sb.append("To");
-    }
-    sb.append(nameCapitalized() + "(int index, " + ofTypeDecl() + " o) {\n");
-      sb.append(ind(2) + "assertNotNull(o);\n");
-      sb.append(ind(2) + "if (o != null && o." + otherSide().getImplAttributeField() + " != null) {\n");
-        sb.append(ind(3) + ASTNode.listClass + "<" + ofTypeDecl() + "> list2 = o." + otherSide().getImplAttributeField() + "." + getImplAttributeField() + ";\n");
-        sb.append(ind(3) + "if (list2.remove(o))\n");
-          sb.append(ind(4) + "o." + otherSide().getImplAttributeField() + ".set" + getImplAttributeName() + "(list2);\n");
-      sb.append(ind(2) + "}\n");
-      sb.append(ind(2) + ASTNode.listClass + "<" + ofTypeDecl() + "> list = " + getImplAttributeField() + ";\n");
-      sb.append(ind(2) + "if (list == null) {\n");
-        sb.append(ind(3) + "list = new " + ASTNode.listClass + "<>();\n");
-      sb.append(ind(2) + "}\n");
-      sb.append(ind(2) + "list.add(index, o);\n");
-      sb.append(ind(2) + "set" + getImplAttributeName() + "(list);\n");
-      sb.append(ind(2) + "o.set" + otherSide().getImplAttributeName() + "(this);\n");
+    sb.append(ind(1) + "public void " + getTypeUse().decl() + ".add" + (useJastAddNames ? "" : "To") + nameCapitalized() + "(int index, " + ofTypeDecl() + " o) {\n");
+    sb.append(ind(2) + "assertNotNull(o);\n");
+    sb.append(ind(2) + "if (o != null && o." + otherSide().getImplAttributeField() + " != null) {\n");
+    sb.append(ind(3) + ASTNode.listClass + "<" + ofTypeDecl() + "> list2 = o." + otherSide().getImplAttributeField() + "." + getImplAttributeField() + ";\n");
+    sb.append(ind(3) + "if (list2.remove(o))\n");
+    sb.append(ind(4) + "o." + otherSide().getImplAttributeField() + ".set" + getImplAttributeName() + "(list2);\n");
+    sb.append(ind(2) + "}\n");
+    sb.append(ind(2) + ASTNode.listClass + "<" + ofTypeDecl() + "> list = " + getImplAttributeField() + ";\n");
+    sb.append(ind(2) + "if (list == null) {\n");
+    sb.append(ind(3) + "list = new " + ASTNode.listClass + "<>();\n");
+    sb.append(ind(2) + "}\n");
+    sb.append(ind(2) + "list.add(index, o);\n");
+    sb.append(ind(2) + "set" + getImplAttributeName() + "(list);\n");
+    sb.append(ind(2) + "o.set" + otherSide().getImplAttributeName() + "(this);\n");
     sb.append(ind(1) + "}\n");
 
     // Remove
-    sb.append(ind(1) + "public void " + getTypeUse().decl() + ".remove");
-    if (!useJastAddNames) {
-      sb.append("From");
-    }
-    sb.append(nameCapitalized() + "(" + ofTypeDecl() + " o) {\n");
+    sb.append(ind(1) + "public void " + getTypeUse().decl() + ".remove" + (useJastAddNames ? "" : "From") + nameCapitalized() + "(" + ofTypeDecl() + " o) {\n");
     sb.append(ind(2) + "assertNotNull(o);\n");
     sb.append(ind(2) + ASTNode.listClass + "<" + ofTypeDecl() + "> list = " + getImplAttributeField() + ";\n");
     sb.append(ind(2) + "if (list != null && list.remove(o)) {\n");
@@ -268,9 +218,6 @@ aspect BackendBidirectionalAPI {
   }
 
   public void RelationComponent.generateBiOneMany(StringBuilder sb) {
-    // Get
-    generateGetOne(sb);
-
     // Set
     sb.append(ind(1) + "public " + getTypeUse().decl() + " " + getTypeUse().decl() + ".set" + nameCapitalized()
       + "(" + ofTypeDecl() + " o) {\n");
@@ -278,11 +225,9 @@ aspect BackendBidirectionalAPI {
       sb.append(ind(2) + "assertNotNull(o);\n");
     }
     sb.append(ind(2) + "if (" + getImplAttributeField() + " != null) {\n");
-    sb.append(ind(3) + ASTNode.listClass + "<" + getTypeUse().decl() + "> list2 = " + getImplAttributeField()
-      + "." + otherSide().getImplAttributeField() + ";\n");
+    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"
-      + otherSide().getImplAttributeName() + "(list2);\n");
+    sb.append(ind(3) + getImplAttributeField() + "." + "set" + otherSide().getImplAttributeName() + "(list2);\n");
     sb.append(ind(2) + "}\n");
     sb.append(ind(2) + "set" + getImplAttributeName() + "(o);\n");
 
@@ -290,8 +235,7 @@ aspect BackendBidirectionalAPI {
     if (isOpt()) {
       sb.append(ind(2) + "if (o != null) {\n");
     }
-    sb.append(ind(ind) + ASTNode.listClass + "<" + getTypeUse().decl() + "> list = o."
-      + otherSide().getImplAttributeField() + ";\n");
+    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");
     sb.append(ind(ind) + "}\n");
@@ -302,9 +246,5 @@ aspect BackendBidirectionalAPI {
     }
     sb.append(ind(2) + "return this;\n");
     sb.append(ind(1) + "}\n");
-
-    if (isOpt()) {
-      generateExtraOptAPI(sb);
-    }
   }
 }
diff --git a/src/main/jastadd/backend/DirectedAPI.jadd b/src/main/jastadd/backend/DirectedAPI.jadd
index 9bece4a42da28790c391ce82c22c2fcbcf510e5e..c390de19d2c140654bfd334b4b4c30de812fc32c 100644
--- a/src/main/jastadd/backend/DirectedAPI.jadd
+++ b/src/main/jastadd/backend/DirectedAPI.jadd
@@ -1,9 +1,6 @@
 aspect BackendDirectedAPI {
 
   public void RelationComponent.generateDirectedZeroOneAPI(StringBuilder sb) {
-    // Get
-    generateGetOne(sb);
-
     // Set
     sb.append(ind(1) + "public " + getTypeUse().decl() + " " + getTypeUse().decl());
     sb.append(".set" + nameCapitalized() + "(" + ofTypeDecl() + " o) {\n");
@@ -13,10 +10,6 @@ aspect BackendDirectedAPI {
     sb.append(ind(2) + "set" + getImplAttributeName() + "(o);\n");
     sb.append(ind(2) + "return this;\n");
     sb.append(ind(1) + "}\n");
-
-    if (isOpt()) {
-      generateExtraOptAPI(sb);
-    }
   }
 
   public void RelationComponent.generateDirectedManyAPI(StringBuilder sb) {
@@ -38,29 +31,25 @@ aspect BackendDirectedAPI {
     // resolve the entire list
     if (resolverHelper | serializer) {
       sb.append(ind(2) + "if (l != null) {\n");
-        sb.append(ind(3) + "boolean changed = false;\n");
-        sb.append(ind(3) + "for (int i = 0; i < l.size(); i++) {\n");
-          sb.append(ind(4) + ofTypeDecl() + " element = l.get(i);\n");
-          sb.append(ind(4) + "if (element.is$Unresolved()) {\n");
-            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) + "l.set(i, resolvedElement);\n");
-          sb.append(ind(4) + "}\n");
-        sb.append(ind(3) + "}\n");
-        sb.append(ind(3) + "if (changed) {\n");
-          sb.append(ind(4) + "set" + getImplAttributeName() + "(l);\n");
-        sb.append(ind(3) + "}\n");
+      sb.append(ind(3) + "boolean changed = false;\n");
+      sb.append(ind(3) + "for (int i = 0; i < l.size(); i++) {\n");
+      sb.append(ind(4) + ofTypeDecl() + " element = l.get(i);\n");
+      sb.append(ind(4) + "if (element." + isUnresolvedMethod + "()) {\n");
+      sb.append(ind(5) + "changed = true;\n");
+      sb.append(ind(5) + ofTypeDecl() + " resolvedElement = resolve" + nameCapitalized() + "ByToken(element." + asUnresolvedMethod + "()." + getUnresolvedTokenMethod + "(), i);\n");
+      sb.append(ind(5) + "l.set(i, resolvedElement);\n");
+      sb.append(ind(4) + "}\n");
+      sb.append(ind(3) + "}\n");
+      sb.append(ind(3) + "if (changed) {\n");
+      sb.append(ind(4) + "set" + getImplAttributeName() + "(l);\n");
+      sb.append(ind(3) + "}\n");
       sb.append(ind(2) + "}\n");
     }
     sb.append(ind(2) + "return l != null ? Collections.unmodifiableList(l) : Collections.emptyList();\n");
     sb.append(ind(1) + "}\n");
 
     // Add
-    sb.append(ind(1) + "public void " + getTypeUse().decl() + ".add");
-    if (!useJastAddNames) {
-      sb.append("To");
-    }
-    sb.append(nameCapitalized() + "(" + ofTypeDecl() + " o) {\n");
+    sb.append(ind(1) + "public void " + getTypeUse().decl() + ".add" + (useJastAddNames ? "" : "To") + nameCapitalized() + "(" + ofTypeDecl() + " o) {\n");
     sb.append(ind(2) + "assertNotNull(o);\n");
     sb.append(ind(2) + ASTNode.listClass + "<" + ofTypeDecl() + "> list = " + getImplAttributeField() + ";\n");
     sb.append(ind(2) + "if (list == null) {\n");
@@ -71,11 +60,7 @@ aspect BackendDirectedAPI {
     sb.append(ind(1) + "}\n");
 
     // Insert / add at specific position
-    sb.append(ind(1) + "public void " + getTypeUse().decl() + ".add");
-    if (!useJastAddNames) {
-      sb.append("To");
-    }
-    sb.append(nameCapitalized() + "(int index, " + ofTypeDecl() + " o) {\n");
+    sb.append(ind(1) + "public void " + getTypeUse().decl() + ".add" + (useJastAddNames ? "" : "To") + nameCapitalized() + "(int index, " + ofTypeDecl() + " o) {\n");
     sb.append(ind(2) + "assertNotNull(o);\n");
     sb.append(ind(2) + ASTNode.listClass + "<" + ofTypeDecl() + "> list = " + getImplAttributeField() + ";\n");
     sb.append(ind(2) + "if (list == null) {\n");
@@ -86,11 +71,7 @@ aspect BackendDirectedAPI {
     sb.append(ind(1) + "}\n");
 
     // Remove
-    sb.append(ind(1) + "public void " + getTypeUse().decl() + ".remove");
-    if (!useJastAddNames) {
-      sb.append("From");
-    }
-    sb.append(nameCapitalized() + "(" + ofTypeDecl() + " o) {\n");
+    sb.append(ind(1) + "public void " + getTypeUse().decl() + ".remove" + (useJastAddNames ? "" : "From") + nameCapitalized() + "(" + ofTypeDecl() + " o) {\n");
     sb.append(ind(2) + "assertNotNull(o);\n");
     sb.append(ind(2) + ASTNode.listClass + "<" + ofTypeDecl() + "> list = " + getImplAttributeField() + ";\n");
     sb.append(ind(2) + "if (list != null && list.remove(o)) {\n");
@@ -98,25 +79,4 @@ aspect BackendDirectedAPI {
     sb.append(ind(2) + "}\n");
     sb.append(ind(1) + "}\n");
   }
-
-  public void RelationComponent.generateGetOne(StringBuilder sb) {
-    sb.append(ind(1) + "public " + ofTypeDecl() + " " + getTypeUse().decl() + ".");
-    if (useJastAddNames) {
-      sb.append("get" + nameCapitalized());
-    } else {
-      sb.append(name());
-    }
-    sb.append("() {\n");
-    if (resolverHelper | serializer) {
-      sb.append(ind(2) + "if (" + getImplAttributeField() + " != null && " + getImplAttributeField() + ".is$Unresolved()) {\n");
-        sb.append(ind(3) + "if (" + getImplAttributeField() + ".as$Unresolved().getUnresolved$ResolveOpposite()) {\n");
-          sb.append(ind(4) + "set" + nameCapitalized() + "(resolve" + nameCapitalized() + "ByToken(" + getImplAttributeField() + ".as$Unresolved().getUnresolved$Token()));\n");
-        sb.append(ind(3) + "} else {\n");
-          sb.append(ind(4) + "set" + getImplAttributeName() + "(resolve" + nameCapitalized() + "ByToken(" + getImplAttributeField() + ".as$Unresolved().getUnresolved$Token()));\n");
-        sb.append(ind(3) + "}\n");
-      sb.append(ind(2) + "}\n");
-    }
-    sb.append(ind(2) + "return get" + getImplAttributeName() + "();\n");
-    sb.append(ind(1) + "}\n");
-  }
 }
diff --git a/src/main/jastadd/backend/NameResolution.jadd b/src/main/jastadd/backend/NameResolution.jadd
index 58194664316ad4d6354424daf9287705c07c0b66..13aa310e9b89b4a6b02a16aef50381b93450b97a 100644
--- a/src/main/jastadd/backend/NameResolution.jadd
+++ b/src/main/jastadd/backend/NameResolution.jadd
@@ -1,5 +1,18 @@
 aspect NameResolutionHelper {
 
+  protected static final String ASTNode.unresolvedPrefix = "Unresolved$";
+  protected static final String ASTNode.isUnresolvedMethod = "is$Unresolved";
+  protected static final String ASTNode.asUnresolvedMethod = "as$Unresolved";
+  protected static final String ASTNode.getUnresolvedTokenMethod = "get" + unresolvedPrefix + "Token";
+  protected static final String ASTNode.getUnresolvedResolveOppositeMethod = "get" + unresolvedPrefix + "ResolveOpposite";
+  protected static final String ASTNode.createReferenceMethod = "createReference";
+  protected static final String ASTNode.createRefMethod = "createRef";
+  protected static final String ASTNode.createRefDirectionMethod = "createRefDirection";
+  protected static final String ASTNode.globallyResolvePrefix = "globallyResolve";
+  protected static final String ASTNode.globallyResolvePostfix = "ByToken";
+  protected static final String ASTNode.resolveAllMethod = "resolveAll";
+  protected static final String ASTNode.treeResolveAllMethod = "treeResolveAll";
+
   public String Program.generateRewriteToSuperTypeStub() {
     StringBuilder sb = new StringBuilder();
     generateRewriteToSuperTypeStub(sb);
@@ -48,8 +61,8 @@ aspect NameResolutionHelper {
 
   public void Program.generateGenericRefCreation(StringBuilder sb) {
     sb.append(ind(1) + "// generic reference creation\n");
-    sb.append(ind(1) + "syn String ASTNode.createReference();\n");
-    sb.append(ind(1) + "eq ASTNode.createReference() {\n");
+    sb.append(ind(1) + "syn String ASTNode." + createReferenceMethod + "();\n");
+    sb.append(ind(1) + "eq ASTNode." + createReferenceMethod + "() {\n");
     sb.append(ind(2) + "throw new RuntimeException(\"Generic reference creation not implemented.\");\n");
     sb.append(ind(1) + "}\n");
   }
@@ -76,15 +89,15 @@ aspect NameResolutionHelper {
     sb.append(ind(1) + "// context-dependent reference creation\n");
     sb.append(ind(1) + "syn String " + getTypeUse().decl() + ".createRefTo" + nameCapitalized() + "(" + ofTypeDecl() + " target) {\n");
     sb.append(ind(2) + "// default to context-independent reference creation\n");
-    sb.append(ind(2) + "return target.createReference();\n");
+    sb.append(ind(2) + "return target." + createReferenceMethod + "();\n");
     sb.append(ind(1) + "}\n");
   }
 
   public void TypeDecl.generateContextIndependentRefCreation(StringBuilder sb) {
     sb.append(ind(1) + "// context-independent reference creation\n");
-    sb.append(ind(1) + "eq " + getID() + ".createReference() {\n");
+    sb.append(ind(1) + "eq " + getID() + "." + createReferenceMethod + "() {\n");
     sb.append(ind(2) + "// default to generic reference creation\n");
-    sb.append(ind(2) + "return super.createReference();\n");
+    sb.append(ind(2) + "return super." + createReferenceMethod + "();\n");
     sb.append(ind(1) + "}\n");
   }
 
@@ -110,9 +123,9 @@ aspect NameResolutionHelper {
 
     sb.append("aspect RefResolverHelpers {\n\n");
 
-    sb.append(ind(1) + "interface Unresolved$Node {\n");
-    sb.append(ind(2) + "String getUnresolved$Token();\n");
-    sb.append(ind(2) + "boolean getUnresolved$ResolveOpposite();\n");
+    sb.append(ind(1) + "interface " + unresolvedPrefix + "Node {\n");
+    sb.append(ind(2) + "String " + getUnresolvedTokenMethod + "();\n");
+    sb.append(ind(2) + "boolean " + getUnresolvedResolveOppositeMethod + "();\n");
     sb.append(ind(1) + "}\n\n");
 
     for (TypeDecl td: getTypeDecls()) {
@@ -131,30 +144,30 @@ aspect NameResolutionHelper {
       throw new RuntimeException("unable to find instantiable subtype for " + getID());
     }
 
-    sb.append(ind(1) + "public static " + getID() + " " + getID() + ".createRef(String ref) {\n");
-      sb.append(ind(2) + "Unresolved$" + instantiableSubType.getID() + " unresolvedNode = new Unresolved$" + instantiableSubType.getID() + "();\n");
-      sb.append(ind(2) + "unresolvedNode.setUnresolved$Token(ref);\n");
-      sb.append(ind(2) + "unresolvedNode.setUnresolved$ResolveOpposite(true);\n");
+    sb.append(ind(1) + "public static " + getID() + " " + getID() + "." + createRefMethod + "(String ref) {\n");
+      sb.append(ind(2) + unresolvedPrefix + instantiableSubType.getID() + " unresolvedNode = new " + unresolvedPrefix + instantiableSubType.getID() + "();\n");
+      sb.append(ind(2) + "unresolvedNode.set" + unresolvedPrefix + "Token(ref);\n");
+      sb.append(ind(2) + "unresolvedNode.set" + unresolvedPrefix + "ResolveOpposite(true);\n");
       sb.append(ind(2) + "return unresolvedNode;\n");
     sb.append(ind(1) + "}\n");
 
-    sb.append(ind(1) + "public static " + getID() + " " + getID() + ".createRefDirection(String ref) {\n");
-      sb.append(ind(2) + "Unresolved$" + instantiableSubType.getID() + " unresolvedNode = new Unresolved$" + instantiableSubType.getID() + "();\n");
-      sb.append(ind(2) + "unresolvedNode.setUnresolved$Token(ref);\n");
-      sb.append(ind(2) + "unresolvedNode.setUnresolved$ResolveOpposite(false);\n");
+    sb.append(ind(1) + "public static " + getID() + " " + getID() + "." + createRefDirectionMethod + "(String ref) {\n");
+      sb.append(ind(2) + unresolvedPrefix + instantiableSubType.getID() + " unresolvedNode = new " + unresolvedPrefix + instantiableSubType.getID() + "();\n");
+      sb.append(ind(2) + "unresolvedNode.set" + unresolvedPrefix + "Token(ref);\n");
+      sb.append(ind(2) + "unresolvedNode.set" + unresolvedPrefix + "ResolveOpposite(false);\n");
       sb.append(ind(2) + "return unresolvedNode;\n");
     sb.append(ind(1) + "}\n");
   }
 
   public void TypeDecl.generateContextIndependentNameResolution(StringBuilder sb) {
     sb.append(ind(1) + "// context-independent name resolution\n");
-    sb.append(ind(1) + "uncache ASTNode.globallyResolve" + getID() + "ByToken(String id);\n");
-    sb.append(ind(1) + "syn " + getID() + " ASTNode.globallyResolve" + getID() + "ByToken(String id) {\n");
+    sb.append(ind(1) + "uncache ASTNode." + globallyResolvePrefix + getID() + globallyResolvePostfix + "(String id);\n");
+    sb.append(ind(1) + "syn " + getID() + " ASTNode." + globallyResolvePrefix + getID() + globallyResolvePostfix + "(String id) {\n");
     if (serializer && !manualReferences) {
       if (jsonPointer) {
         sb.append(ind(2) + "return (" + getID() + ") resolveJsonPointer(id);\n");
       } else {
-        sb.append(ind(2) + "return (" + getID() + ") globallyResolveASTNodeByUID(id);\n");
+        sb.append(ind(2) + "return (" + getID() + ") " + globallyResolvePrefix + "ASTNodeByUID(id);\n");
       }
     } else {
       sb.append(ind(2) + "// perform context independent name resolution here using the id\n");
@@ -193,56 +206,56 @@ aspect NameResolutionHelper {
   public void ManyRelationComponent.generateContextDependentNameResolution(StringBuilder sb) {
 
     if (serializer && !resolverHelper) {
-      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) + ofTypeDecl() + " " + getTypeUse().decl() + ".resolve" + nameCapitalized() + globallyResolvePostfix + "(String id, int position) {\n");
+        sb.append(ind(2) + "return (" + ofTypeDecl() + ") " + globallyResolvePrefix + "ASTNodeByUID(id);\n");
       sb.append(ind(1) + "}\n");
     } else {
       sb.append(ind(1) + "// context-dependent name resolution\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(1) + "uncache " + getTypeUse().decl() + ".resolve" + nameCapitalized() + globallyResolvePostfix + "(String id, int position);\n");
+      sb.append(ind(1) + "syn " + ofTypeDecl() + " " + getTypeUse().decl() + ".resolve" + nameCapitalized() + globallyResolvePostfix + "(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(2) + "return " + globallyResolvePrefix + ofTypeDecl() + globallyResolvePostfix + "(id);\n");
       sb.append(ind(1) + "}\n");
     }
   }
 
   public void RelationComponent.generateDirectedContextDependentNameResolution(StringBuilder sb) {
     if (serializer && !resolverHelper) {
-      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) + ofTypeDecl() + " " + getTypeUse().decl() + ".resolve" + nameCapitalized() + globallyResolvePostfix + "(String id) {\n");
+        sb.append(ind(2) + "return (" + ofTypeDecl() + ") " + globallyResolvePrefix + "ASTNodeByUID(id);\n");
       sb.append(ind(1) + "}\n");
     } else {
       sb.append(ind(1) + "// context-dependent name resolution\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(1) + "uncache " + getTypeUse().decl() + ".resolve" + nameCapitalized() + globallyResolvePostfix + "(String id);\n");
+      sb.append(ind(1) + "syn " + ofTypeDecl() + " " + getTypeUse().decl() + ".resolve" + nameCapitalized() + globallyResolvePostfix + "(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(2) + "return " + globallyResolvePrefix + ofTypeDecl() + globallyResolvePostfix + "(id);\n");
       sb.append(ind(1) + "}\n");
     }
   }
 
   public void Program.resolveAll(StringBuilder sb) {
     sb.append(ind(1) + "// enforce resolving of all non-containment relations of the current non-terminal\n");
-    sb.append(ind(1) + "public void ASTNode.resolveAll() {\n");
+    sb.append(ind(1) + "public void ASTNode." + resolveAllMethod + "() {\n");
     sb.append(ind(1) + "}\n\n");
 
     sb.append(ind(1) + "// enforce resolving in the entire subtree\n");
-    sb.append(ind(1) + "public void ASTNode.treeResolveAll() {\n");
+    sb.append(ind(1) + "public void ASTNode." + treeResolveAllMethod + "() {\n");
       sb.append(ind(2) + "if (children != null) {\n");
         sb.append(ind(3) + "for (int i = 0; i < numChildren; ++i) {\n");
           sb.append(ind(4) + "ASTNode child = children[i];\n");
           sb.append(ind(4) + "if (child != null) {\n");
-            sb.append(ind(5) + "child.treeResolveAll();\n");
+            sb.append(ind(5) + "child." + treeResolveAllMethod + "();\n");
           sb.append(ind(4) + "}\n");
         sb.append(ind(3) + "}\n");
       sb.append(ind(2) + "}\n");
-      sb.append(ind(2) + "resolveAll();\n");
+      sb.append(ind(2) + resolveAllMethod + "();\n");
     sb.append(ind(1) + "}\n");
   }
 
   public void TypeDecl.resolveAll(StringBuilder sb) {
     sb.append(ind(1) + "// enforce resolving of all non-containment relations of the current non-terminal\n");
-    sb.append(ind(1) + "public void " + getID() + ".resolveAll() {\n");
+    sb.append(ind(1) + "public void " + getID() + "." + resolveAllMethod + "() {\n");
     for (RelationComponent relationComponent : relationComponents()) {
       sb.append(ind(2));
       if (useJastAddNames) {
@@ -252,7 +265,7 @@ aspect NameResolutionHelper {
       }
       sb.append(relationComponent.isList() && useJastAddNames ? "List" : "").append("();\n");
     }
-      sb.append(ind(2) + "super.resolveAll();\n");
+      sb.append(ind(2) + "super." + resolveAllMethod + "();\n");
     sb.append(ind(1) + "}\n");
   }
 }