diff --git a/aliasDefinition/Data_alias/Data_alias.aod b/aliasDefinition/Data_alias/Data_alias.aod
index 1152a6f3c33a86974ad37a99353c12e966c88798..c4708e103f70a4fb1a6e98a9ad4bc6c5f2791579 100644
--- a/aliasDefinition/Data_alias/Data_alias.aod
+++ b/aliasDefinition/Data_alias/Data_alias.aod
@@ -3887,8 +3887,8 @@
                 <name>ATTRIBUTE_TYPE</name>
                 <dbName></dbName>
                 <primaryKey v="false" />
-                <columnType v="12" />
-                <size v="63" />
+                <columnType v="1" />
+                <size v="36" />
                 <scale v="0" />
                 <notNull v="true" />
                 <isUnique v="false" />
diff --git a/application/_____SYSTEM_APPLICATION_NEON/_____SYSTEM_APPLICATION_NEON.aod b/application/_____SYSTEM_APPLICATION_NEON/_____SYSTEM_APPLICATION_NEON.aod
index 62ece4463e7ca38fba4d6f66e7412ff80dd73082..882d012d12af9d28493c83d0478e4ad1abc3fc75 100644
--- a/application/_____SYSTEM_APPLICATION_NEON/_____SYSTEM_APPLICATION_NEON.aod
+++ b/application/_____SYSTEM_APPLICATION_NEON/_____SYSTEM_APPLICATION_NEON.aod
@@ -30,7 +30,8 @@
       <icon>VAADIN:CONTROLLER</icon>
       <node name="Group3" kind="123" title="">
         <node name="Attribute_context" kind="10077" />
-        <node name="Keyword_context" kind="10077" />
+        <node name="KeywordEntry_context" kind="10077" />
+        <node name="KeywordAttribute_context" kind="10077" />
         <node name="INTERNAL_ADMINISTRATOR" kind="159" />
       </node>
     </node>
diff --git a/entity/Activity_entity/entityfields/category/possibleItemsProcess.js b/entity/Activity_entity/entityfields/category/possibleItemsProcess.js
index 168963b6169be0c94c701a7633a6ad8c1ef6f73a..921a43cb3947bb30cb50efd44320d7418e0200d7 100644
--- a/entity/Activity_entity/entityfields/category/possibleItemsProcess.js
+++ b/entity/Activity_entity/entityfields/category/possibleItemsProcess.js
@@ -1,5 +1,5 @@
 import("system.result");
 import("Keyword_lib");
 
-var items = KeywordUtils.getStandardArray("ACTIVITY.CATEGORY");
+var items = LegacyKeywordUtils.getStandardArray("ACTIVITY.CATEGORY");
 result.object(items);
\ No newline at end of file
diff --git a/entity/Activity_entity/entityfields/icon/valueProcess.js b/entity/Activity_entity/entityfields/icon/valueProcess.js
index b77beeec11507c78d1c9397de5ac9d8ea3676cc0..6cb990d62b05f123426dfa2e60d2b377aa4afa62 100644
--- a/entity/Activity_entity/entityfields/icon/valueProcess.js
+++ b/entity/Activity_entity/entityfields/icon/valueProcess.js
@@ -4,7 +4,7 @@ import("system.neon");
 import("Keyword_lib");
 
 var category = vars.getString("$field.CATEGORY");
-var kwd = KeywordUtils.createKeyword("ACTIVITY.CATEGORY");
+var kwd = LegacyKeywordUtils.createKeyword("ACTIVITY.CATEGORY");
 var icon = kwd.getPropForKey(category, "defaultAvatarRepresentation", true);
 
 result.string(icon || "NEON:HISTORY");
diff --git a/entity/Activity_entity/entityfields/subject_details/valueProcess.js b/entity/Activity_entity/entityfields/subject_details/valueProcess.js
index 3cba44d10afbf3f366822381953ae1e3463a523e..54c6e810026576c01cf069b5170c47972ab83fa5 100644
--- a/entity/Activity_entity/entityfields/subject_details/valueProcess.js
+++ b/entity/Activity_entity/entityfields/subject_details/valueProcess.js
@@ -5,5 +5,5 @@ import("Keyword_lib");
 var histMedium;
 histMedium = vars.get("$field.CATEGORY");
 if (histMedium){
-    result.string(vars.get("$field.SUBJECT") + " (" + KeywordUtils.getViewValue("ACTIVITY.CATEGORY", histMedium) + ")");
+    result.string(vars.get("$field.SUBJECT") + " (" + LegacyKeywordUtils.getViewValue("ACTIVITY.CATEGORY", histMedium) + ")");
 }
\ No newline at end of file
diff --git a/entity/Address_entity/entityfields/addr_type/possibleItemsProcess.js b/entity/Address_entity/entityfields/addr_type/possibleItemsProcess.js
index 304ab1c8013a634350d75937222f2fccb54dfe6a..f65e4812fc2a1ea6e3d3c46d4cf3deeba893134e 100644
--- a/entity/Address_entity/entityfields/addr_type/possibleItemsProcess.js
+++ b/entity/Address_entity/entityfields/addr_type/possibleItemsProcess.js
@@ -21,7 +21,7 @@ if (vars.exists("$param.ContactType_param") && parseInt(vars.get("$param.Contact
     }
 
     var resultKeywords = [];
-    KeywordUtils.getStandardArrayProps("ADDRESS.TYPE").forEach(function(pKeyword) {
+    LegacyKeywordUtils.getStandardArrayProps("ADDRESS.TYPE").forEach(function(pKeyword) {
         for (let i = 0; i < fields.length; i++) {
             if (pKeyword[2][fields[i]]) {
                 resultKeywords.push([pKeyword[0], pKeyword[1]]);
diff --git a/entity/Communication_entity/entityfields/addr/contentTypeProcess.js b/entity/Communication_entity/entityfields/addr/contentTypeProcess.js
index 734b617ebd9de9c05452c2fb1bfbde995957f891..a960f567b9adb79d447efe58f6e7bbbb12bd48d1 100644
--- a/entity/Communication_entity/entityfields/addr/contentTypeProcess.js
+++ b/entity/Communication_entity/entityfields/addr/contentTypeProcess.js
@@ -7,7 +7,7 @@ var medium, contentType;
 //TODO: add constants for contentTypes #1022547
 medium = vars.get("$field.MEDIUM_ID");
 if (medium){
-    contentType = KeywordUtils.createKeyword("COMMUNICATION.MEDIUM").getPropForKey(medium, "contentType", true) || "TEXT";
+    contentType = LegacyKeywordUtils.createKeyword("COMMUNICATION.MEDIUM").getPropForKey(medium, "contentType", true) || "TEXT";
 }
 else {
     contentType = "TEXT";
diff --git a/entity/Communication_entity/entityfields/addr/onValidation.js b/entity/Communication_entity/entityfields/addr/onValidation.js
index d891aa3a27aa5b3ba45191d69a6121292efbc544..bf2171c209dd9e13aceb6c2601f1f7269db9c3a4 100644
--- a/entity/Communication_entity/entityfields/addr/onValidation.js
+++ b/entity/Communication_entity/entityfields/addr/onValidation.js
@@ -8,7 +8,7 @@ import("Communication_lib");
 import("Util_lib");
 import("Entity_lib");
 
-var kwd = KeywordUtils.createKeyword("COMMUNICATION.MEDIUM");
+var kwd = LegacyKeywordUtils.createKeyword("COMMUNICATION.MEDIUM");
 var commMedium = vars.get("$field.MEDIUM_ID");
 var commCategory = kwd.getPropForKey(commMedium, "contentType", true);//TODO: maybe accessible via  $property - then it's not needed to keep this information within the keyword
 
diff --git a/entity/Communication_entity/entityfields/medium_id/possibleItemsProcess.js b/entity/Communication_entity/entityfields/medium_id/possibleItemsProcess.js
index 239221207238610962d98fd00adad5ccedf98e85..c92cbb2549430a0337918745657dc796bb21c2ff 100644
--- a/entity/Communication_entity/entityfields/medium_id/possibleItemsProcess.js
+++ b/entity/Communication_entity/entityfields/medium_id/possibleItemsProcess.js
@@ -3,5 +3,5 @@ import("system.vars");
 import("system.result");
 import("Keyword_lib");
 
-var items = KeywordUtils.getStandardArray("COMMUNICATION.MEDIUM");
+var items = LegacyKeywordUtils.getStandardArray("COMMUNICATION.MEDIUM");
 result.object(items);
diff --git a/entity/Communication_entity/entityfields/medium_id/valueMappingProcess.js b/entity/Communication_entity/entityfields/medium_id/valueMappingProcess.js
index 9c59823cfa09ef0ba1b7c0357b1c6c57c17395f5..a567223ae010bfe6382ee6e14fa7449fc4e1d670 100644
--- a/entity/Communication_entity/entityfields/medium_id/valueMappingProcess.js
+++ b/entity/Communication_entity/entityfields/medium_id/valueMappingProcess.js
@@ -3,5 +3,5 @@ import("Keyword_lib");
 
 var kwdUtils, items;
 
-items = KeywordUtils.getStandardArray("COMMUNICATION.MEDIUM");
+items = LegacyKeywordUtils.getStandardArray("COMMUNICATION.MEDIUM");
 result.object(items);
\ No newline at end of file
diff --git a/entity/KeywordAttributeRelation_entity/KeywordAttributeRelation_entity.aod b/entity/KeywordAttributeRelation_entity/KeywordAttributeRelation_entity.aod
new file mode 100644
index 0000000000000000000000000000000000000000..c7bfef823a151b1250bf7e22ecb8c2406b763f6b
--- /dev/null
+++ b/entity/KeywordAttributeRelation_entity/KeywordAttributeRelation_entity.aod
@@ -0,0 +1,133 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<entity xmlns="http://www.adito.de/2018/ao/Model" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" VERSION="1.2.0" xsi:schemaLocation="http://www.adito.de/2018/ao/Model adito://models/xsd/entity/1.2.0">
+  <name>KeywordAttributeRelation_entity</name>
+  <title>Keyword Attribute Values</title>
+  <majorModelMode>DISTRIBUTED</majorModelMode>
+  <recordContainer>db</recordContainer>
+  <entityFields>
+    <entityProvider>
+      <name>#PROVIDER</name>
+    </entityProvider>
+    <entityField>
+      <name>AB_KEYWORD_ATTRIBUTERELATIONID</name>
+      <mandatory v="true" />
+      <valueProcess>%aditoprj%/entity/KeywordAttributeRelation_entity/entityfields/ab_keyword_attributerelationid/valueProcess.js</valueProcess>
+    </entityField>
+    <entityField>
+      <name>CHAR_VALUE</name>
+    </entityField>
+    <entityField>
+      <name>NUMBER_VALUE</name>
+    </entityField>
+    <entityField>
+      <name>BOOL_VALUE</name>
+    </entityField>
+    <entityField>
+      <name>AB_KEYWORD_ATTRIBUTE_ID</name>
+      <title>Keyword Attribute</title>
+      <consumer>KeywordAttributes</consumer>
+      <mandatory v="true" />
+    </entityField>
+    <entityField>
+      <name>AB_KEYWORD_ENTRY_ID</name>
+      <mandatory v="true" />
+      <valueProcess>%aditoprj%/entity/KeywordAttributeRelation_entity/entityfields/ab_keyword_entry_id/valueProcess.js</valueProcess>
+    </entityField>
+    <entityProvider>
+      <name>SpecificContainer</name>
+      <fieldType>DEPENDENCY_IN</fieldType>
+      <title></title>
+      <recordContainer>db</recordContainer>
+      <dependencies>
+        <entityDependency>
+          <name>490d12c0-6ace-42e5-89e1-d40b25322161</name>
+          <entityName>KeywordEntry_entity</entityName>
+          <fieldName>KeywordAttributeRelations</fieldName>
+          <isConsumer v="false" />
+        </entityDependency>
+      </dependencies>
+    </entityProvider>
+    <entityParameter>
+      <name>containerName_param</name>
+      <expose v="true" />
+      <triggerRecalculation v="true" />
+      <description>PARAMETER</description>
+    </entityParameter>
+    <entityConsumer>
+      <name>KeywordAttributes</name>
+      <fieldType>DEPENDENCY_OUT</fieldType>
+      <dependency>
+        <name>dependency</name>
+        <entityName>KeywordAttribute_entity</entityName>
+        <fieldName>SpecificContainerKeywords</fieldName>
+      </dependency>
+      <children>
+        <entityParameter>
+          <name>containerName_param</name>
+          <code>%aditoprj%/entity/KeywordAttributeRelation_entity/entityfields/keywordattributes/children/containername_param/code.js</code>
+        </entityParameter>
+        <entityParameter>
+          <name>filterAlreadyUsedByEntryId_param</name>
+          <code>%aditoprj%/entity/KeywordAttributeRelation_entity/entityfields/keywordattributes/children/filteralreadyusedbyentryid_param/code.js</code>
+        </entityParameter>
+      </children>
+    </entityConsumer>
+    <entityParameter>
+      <name>keywordEntry_param</name>
+      <expose v="true" />
+      <triggerRecalculation v="true" />
+      <mandatory v="true" />
+      <description>PARAMETER</description>
+    </entityParameter>
+    <entityField>
+      <name>VALUE_PROXY</name>
+      <documentation>%aditoprj%/entity/KeywordAttributeRelation_entity/entityfields/value_proxy/documentation.adoc</documentation>
+      <valueProcess>%aditoprj%/entity/KeywordAttributeRelation_entity/entityfields/value_proxy/valueProcess.js</valueProcess>
+    </entityField>
+  </entityFields>
+  <recordContainers>
+    <dbRecordContainer>
+      <name>db</name>
+      <alias>Data_alias</alias>
+      <linkInformation>
+        <linkInformation>
+          <name>a52883ee-630c-4373-a4ad-9b1e8c3e8188</name>
+          <tableName>AB_KEYWORD_ATTRIBUTERELATION</tableName>
+          <primaryKey>AB_KEYWORD_ATTRIBUTERELATIONID</primaryKey>
+          <isUIDTable v="true" />
+          <readonly v="false" />
+        </linkInformation>
+      </linkInformation>
+      <recordFieldMappings>
+        <dbRecordFieldMapping>
+          <name>AB_KEYWORD_ATTRIBUTERELATIONID.value</name>
+          <recordfield>AB_KEYWORD_ATTRIBUTERELATION.AB_KEYWORD_ATTRIBUTERELATIONID</recordfield>
+        </dbRecordFieldMapping>
+        <dbRecordFieldMapping>
+          <name>BOOL_VALUE.value</name>
+          <recordfield>AB_KEYWORD_ATTRIBUTERELATION.BOOL_VALUE</recordfield>
+        </dbRecordFieldMapping>
+        <dbRecordFieldMapping>
+          <name>CHAR_VALUE.value</name>
+          <recordfield>AB_KEYWORD_ATTRIBUTERELATION.CHAR_VALUE</recordfield>
+        </dbRecordFieldMapping>
+        <dbRecordFieldMapping>
+          <name>NUMBER_VALUE.value</name>
+          <recordfield>AB_KEYWORD_ATTRIBUTERELATION.NUMBER_VALUE</recordfield>
+        </dbRecordFieldMapping>
+        <dbRecordFieldMapping>
+          <name>AB_KEYWORD_ATTRIBUTE_ID.value</name>
+          <recordfield>AB_KEYWORD_ATTRIBUTERELATION.AB_KEYWORD_ATTRIBUTE_ID</recordfield>
+        </dbRecordFieldMapping>
+        <dbRecordFieldMapping>
+          <name>AB_KEYWORD_ENTRY_ID.value</name>
+          <recordfield>AB_KEYWORD_ATTRIBUTERELATION.AB_KEYWORD_ENTRY_ID</recordfield>
+        </dbRecordFieldMapping>
+        <dbRecordFieldMapping>
+          <name>AB_KEYWORD_ATTRIBUTE_ID.displayValue</name>
+          <expression>%aditoprj%/entity/KeywordAttributeRelation_entity/recordcontainers/db/recordfieldmappings/ab_keyword_attribute_id.displayvalue/expression.js</expression>
+        </dbRecordFieldMapping>
+      </recordFieldMappings>
+    </dbRecordContainer>
+  </recordContainers>
+</entity>
diff --git a/entity/KeywordAttributeRelation_entity/entityfields/ab_keyword_attributerelationid/valueProcess.js b/entity/KeywordAttributeRelation_entity/entityfields/ab_keyword_attributerelationid/valueProcess.js
new file mode 100644
index 0000000000000000000000000000000000000000..4af99287f59a86e98d9b4c552c010fe13c106cc7
--- /dev/null
+++ b/entity/KeywordAttributeRelation_entity/entityfields/ab_keyword_attributerelationid/valueProcess.js
@@ -0,0 +1,7 @@
+import("system.util");
+import("system.result");
+import("system.neon");
+import("system.vars");
+
+if(vars.get("$sys.recordstate") == neon.OPERATINGSTATE_NEW)
+    result.string(util.getNewUUID());
\ No newline at end of file
diff --git a/entity/KeywordAttributeRelation_entity/entityfields/ab_keyword_entry_id/valueProcess.js b/entity/KeywordAttributeRelation_entity/entityfields/ab_keyword_entry_id/valueProcess.js
new file mode 100644
index 0000000000000000000000000000000000000000..6a057300b2bb369ed866518193c9282931956dfb
--- /dev/null
+++ b/entity/KeywordAttributeRelation_entity/entityfields/ab_keyword_entry_id/valueProcess.js
@@ -0,0 +1,8 @@
+import("system.util");
+import("system.result");
+import("system.neon");
+import("system.vars");
+
+var keywordEntryId = vars.get("$param.keywordEntry_param");
+if(keywordEntryId && vars.get("$sys.recordstate") == neon.OPERATINGSTATE_NEW)
+    result.string(keywordEntryId);
\ No newline at end of file
diff --git a/entity/KeywordAttributeRelation_entity/entityfields/keywordattributes/children/containername_param/code.js b/entity/KeywordAttributeRelation_entity/entityfields/keywordattributes/children/containername_param/code.js
new file mode 100644
index 0000000000000000000000000000000000000000..04bac245422e16f11fa07dfd8ff7de51343d2148
--- /dev/null
+++ b/entity/KeywordAttributeRelation_entity/entityfields/keywordattributes/children/containername_param/code.js
@@ -0,0 +1,4 @@
+import("system.vars");
+import("system.result");
+
+result.string(vars.get("$param.containerName_param"));
\ No newline at end of file
diff --git a/entity/KeywordAttributeRelation_entity/entityfields/keywordattributes/children/filteralreadyusedbyentryid_param/code.js b/entity/KeywordAttributeRelation_entity/entityfields/keywordattributes/children/filteralreadyusedbyentryid_param/code.js
new file mode 100644
index 0000000000000000000000000000000000000000..f488dd168118d6d24130f83960ad4f4f59226a52
--- /dev/null
+++ b/entity/KeywordAttributeRelation_entity/entityfields/keywordattributes/children/filteralreadyusedbyentryid_param/code.js
@@ -0,0 +1,4 @@
+import("system.vars");
+import("system.result");
+
+result.string(vars.get("$field.AB_KEYWORD_ENTRY_ID"));
\ No newline at end of file
diff --git a/entity/KeywordAttributeRelation_entity/entityfields/value_proxy/documentation.adoc b/entity/KeywordAttributeRelation_entity/entityfields/value_proxy/documentation.adoc
new file mode 100644
index 0000000000000000000000000000000000000000..51ce71eb3b829375c143714f88dd8c10ebfb0096
--- /dev/null
+++ b/entity/KeywordAttributeRelation_entity/entityfields/value_proxy/documentation.adoc
@@ -0,0 +1 @@
+A field that is proxy for the correct value-fields like `CHAR_VALUE`, `CHAR_BOOL`, etc.
\ No newline at end of file
diff --git a/entity/KeywordAttributeRelation_entity/entityfields/value_proxy/valueProcess.js b/entity/KeywordAttributeRelation_entity/entityfields/value_proxy/valueProcess.js
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/entity/KeywordAttributeRelation_entity/recordcontainers/db/recordfieldmappings/ab_keyword_attribute_id.displayvalue/expression.js b/entity/KeywordAttributeRelation_entity/recordcontainers/db/recordfieldmappings/ab_keyword_attribute_id.displayvalue/expression.js
new file mode 100644
index 0000000000000000000000000000000000000000..486af1540ab5c12fa5013e4d2da2306990e97273
--- /dev/null
+++ b/entity/KeywordAttributeRelation_entity/recordcontainers/db/recordfieldmappings/ab_keyword_attribute_id.displayvalue/expression.js
@@ -0,0 +1,5 @@
+import("system.result");
+
+result.string("select AB_KEYWORD_ATTRIBUTE.NAME "
+    + "from AB_KEYWORD_ATTRIBUTE "
+    + "where AB_KEYWORD_ATTRIBUTE.AB_KEYWORD_ATTRIBUTEID = AB_KEYWORD_ATTRIBUTERELATION.AB_KEYWORD_ATTRIBUTE_ID");
\ No newline at end of file
diff --git a/entity/KeywordAttribute_entity/KeywordAttribute_entity.aod b/entity/KeywordAttribute_entity/KeywordAttribute_entity.aod
new file mode 100644
index 0000000000000000000000000000000000000000..4061a215b27e5eeefbc5529ab48ed631eb1a2f09
--- /dev/null
+++ b/entity/KeywordAttribute_entity/KeywordAttribute_entity.aod
@@ -0,0 +1,115 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<entity xmlns="http://www.adito.de/2018/ao/Model" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" VERSION="1.2.0" xsi:schemaLocation="http://www.adito.de/2018/ao/Model adito://models/xsd/entity/1.2.0">
+  <name>KeywordAttribute_entity</name>
+  <title>Keyword Attribute</title>
+  <majorModelMode>DISTRIBUTED</majorModelMode>
+  <iconId>VAADIN:KEY_O</iconId>
+  <iconIdProcess>%aditoprj%/entity/KeywordAttribute_entity/iconIdProcess.js</iconIdProcess>
+  <titleProcess>%aditoprj%/entity/KeywordAttribute_entity/titleProcess.js</titleProcess>
+  <recordContainer>db</recordContainer>
+  <entityFields>
+    <entityProvider>
+      <name>#PROVIDER</name>
+    </entityProvider>
+    <entityField>
+      <name>AB_KEYWORD_ATTRIBUTEID</name>
+      <valueProcess>%aditoprj%/entity/KeywordAttribute_entity/entityfields/ab_keyword_attributeid/valueProcess.js</valueProcess>
+    </entityField>
+    <entityField>
+      <name>CONTAINER</name>
+      <title>Container</title>
+      <mandatory v="true" />
+      <possibleItemsProcess>%aditoprj%/entity/KeywordAttribute_entity/entityfields/container/possibleItemsProcess.js</possibleItemsProcess>
+    </entityField>
+    <entityField>
+      <name>NAME</name>
+      <title>Name</title>
+      <mandatory v="true" />
+      <onValidation>%aditoprj%/entity/KeywordAttribute_entity/entityfields/name/onValidation.js</onValidation>
+    </entityField>
+    <entityField>
+      <name>TYPE</name>
+      <title>Type</title>
+      <consumer>KeywordKeywordAttributeTypes</consumer>
+      <mandatory v="true" />
+    </entityField>
+    <entityProvider>
+      <name>SpecificContainerKeywords</name>
+      <fieldType>DEPENDENCY_IN</fieldType>
+      <recordContainer>db</recordContainer>
+      <dependencies>
+        <entityDependency>
+          <name>1d11c064-1cf2-4f08-b842-9fa941ad3157</name>
+          <entityName>KeywordAttributeRelation_entity</entityName>
+          <fieldName>KeywordAttributes</fieldName>
+          <isConsumer v="false" />
+        </entityDependency>
+      </dependencies>
+    </entityProvider>
+    <entityParameter>
+      <name>containerName_param</name>
+      <expose v="true" />
+      <triggerRecalculation v="true" />
+      <description>PARAMETER</description>
+    </entityParameter>
+    <entityParameter>
+      <name>filterAlreadyUsedByEntryId_param</name>
+      <expose v="true" />
+      <mandatory v="false" />
+      <description>PARAMETER</description>
+    </entityParameter>
+    <entityConsumer>
+      <name>KeywordKeywordAttributeTypes</name>
+      <fieldType>DEPENDENCY_OUT</fieldType>
+      <dependency>
+        <name>dependency</name>
+        <entityName>KeywordEntry_entity</entityName>
+        <fieldName>SpecificContainerKeywords</fieldName>
+      </dependency>
+      <children>
+        <entityParameter>
+          <name>containerName_param</name>
+          <code>%aditoprj%/entity/KeywordAttribute_entity/entityfields/keywordkeywordattributetypes/children/containername_param/code.js</code>
+        </entityParameter>
+      </children>
+    </entityConsumer>
+  </entityFields>
+  <recordContainers>
+    <dbRecordContainer>
+      <name>db</name>
+      <alias>Data_alias</alias>
+      <conditionProcess>%aditoprj%/entity/KeywordAttribute_entity/recordcontainers/db/conditionProcess.js</conditionProcess>
+      <linkInformation>
+        <linkInformation>
+          <name>bd113d67-34ab-4708-b0e5-60a44332e6b8</name>
+          <tableName>AB_KEYWORD_ATTRIBUTE</tableName>
+          <primaryKey>AB_KEYWORD_ATTRIBUTEID</primaryKey>
+          <isUIDTable v="true" />
+          <readonly v="false" />
+        </linkInformation>
+      </linkInformation>
+      <recordFieldMappings>
+        <dbRecordFieldMapping>
+          <name>AB_KEYWORD_ATTRIBUTEID.value</name>
+          <recordfield>AB_KEYWORD_ATTRIBUTE.AB_KEYWORD_ATTRIBUTEID</recordfield>
+        </dbRecordFieldMapping>
+        <dbRecordFieldMapping>
+          <name>CONTAINER.value</name>
+          <recordfield>AB_KEYWORD_ATTRIBUTE.CONTAINER</recordfield>
+        </dbRecordFieldMapping>
+        <dbRecordFieldMapping>
+          <name>NAME.value</name>
+          <recordfield>AB_KEYWORD_ATTRIBUTE.NAME</recordfield>
+        </dbRecordFieldMapping>
+        <dbRecordFieldMapping>
+          <name>TYPE.value</name>
+          <recordfield>AB_KEYWORD_ATTRIBUTE.TYPE</recordfield>
+        </dbRecordFieldMapping>
+        <dbRecordFieldMapping>
+          <name>TYPE.displayValue</name>
+          <expression>%aditoprj%/entity/KeywordAttribute_entity/recordcontainers/db/recordfieldmappings/type.displayvalue/expression.js</expression>
+        </dbRecordFieldMapping>
+      </recordFieldMappings>
+    </dbRecordContainer>
+  </recordContainers>
+</entity>
diff --git a/entity/KeywordAttribute_entity/entityfields/ab_keyword_attributeid/valueProcess.js b/entity/KeywordAttribute_entity/entityfields/ab_keyword_attributeid/valueProcess.js
new file mode 100644
index 0000000000000000000000000000000000000000..4af99287f59a86e98d9b4c552c010fe13c106cc7
--- /dev/null
+++ b/entity/KeywordAttribute_entity/entityfields/ab_keyword_attributeid/valueProcess.js
@@ -0,0 +1,7 @@
+import("system.util");
+import("system.result");
+import("system.neon");
+import("system.vars");
+
+if(vars.get("$sys.recordstate") == neon.OPERATINGSTATE_NEW)
+    result.string(util.getNewUUID());
\ No newline at end of file
diff --git a/entity/KeywordAttribute_entity/entityfields/container/possibleItemsProcess.js b/entity/KeywordAttribute_entity/entityfields/container/possibleItemsProcess.js
new file mode 100644
index 0000000000000000000000000000000000000000..50a930c3f4bcd04477c5c217fe2fb7c26294309e
--- /dev/null
+++ b/entity/KeywordAttribute_entity/entityfields/container/possibleItemsProcess.js
@@ -0,0 +1,7 @@
+import("system.result");
+import("Keyword_lib");
+
+var res = KeywordUtils.getContainerNames().map(function(e){
+    return [e, e];//currently the first column is ID, second view value - which is the same because there is no ID for keyword-containers
+});
+result.object(res);
\ No newline at end of file
diff --git a/entity/KeywordAttribute_entity/entityfields/keywordkeywordattributetypes/children/containername_param/code.js b/entity/KeywordAttribute_entity/entityfields/keywordkeywordattributetypes/children/containername_param/code.js
new file mode 100644
index 0000000000000000000000000000000000000000..aee5aa764b590de8807fb1e55b2ebbe4d3900295
--- /dev/null
+++ b/entity/KeywordAttribute_entity/entityfields/keywordkeywordattributetypes/children/containername_param/code.js
@@ -0,0 +1,4 @@
+import("system.result");
+import("Keyword_lib");
+
+result.string($KeywordRegistry.get.KeywordAttributeType);
\ No newline at end of file
diff --git a/entity/KeywordAttribute_entity/entityfields/name/onValidation.js b/entity/KeywordAttribute_entity/entityfields/name/onValidation.js
new file mode 100644
index 0000000000000000000000000000000000000000..6a2c9b1a35a48af4deb4794848269fca517e8b50
--- /dev/null
+++ b/entity/KeywordAttribute_entity/entityfields/name/onValidation.js
@@ -0,0 +1,30 @@
+import("system.translate");
+import("system.result");
+import("system.db");
+import("system.vars");
+import("system.neon");
+import("Sql_lib");
+import("Entity_lib");
+
+//Name has to be unique within one Keyword-Container because you may want to retrieve a keyword-attribute-value by name
+var validation = (function(){
+    if (vars.get("$sys.recordstate") != neon.OPERATINGSTATE_NEW)
+        return null;
+    var container = vars.get("$field.CONTAINER");
+    if (container == "")
+        return null;
+    var name = ProcessHandlingUtils.getOnValidationValue(vars.get("$field.NAME"));
+    if (name == "")
+        return null;
+    
+    var cond = SqlCondition.begin().andPrepare("AB_KEYWORD_ATTRIBUTE.CONTAINER", container)
+                                   .andPrepare("AB_KEYWORD_ATTRIBUTE.name", name);
+    var alreadyExistingCount = db.cell(cond.buildSql("select count(*) from AB_KEYWORD_ATTRIBUTE"));
+    if (alreadyExistingCount != "0")
+        return translate.withArguments("Name \"%0\" already used for container \"%1\"", [name, container]);
+    
+    return null;
+})();
+
+if (validation)
+    result.string(validation);
\ No newline at end of file
diff --git a/entity/KeywordAttribute_entity/iconIdProcess.js b/entity/KeywordAttribute_entity/iconIdProcess.js
new file mode 100644
index 0000000000000000000000000000000000000000..ef0457e780554daacf633e3381aff300f84e713c
--- /dev/null
+++ b/entity/KeywordAttribute_entity/iconIdProcess.js
@@ -0,0 +1,7 @@
+import("system.vars");
+import("system.result");
+
+var container = vars.get("$field.CONTAINER");
+
+if (container)
+    result.string("TEXT:" + container);
\ No newline at end of file
diff --git a/entity/KeywordAttribute_entity/recordcontainers/db/conditionProcess.js b/entity/KeywordAttribute_entity/recordcontainers/db/conditionProcess.js
new file mode 100644
index 0000000000000000000000000000000000000000..3d1602c7ef941c6fd534533fcf4d21c58b96d879
--- /dev/null
+++ b/entity/KeywordAttribute_entity/recordcontainers/db/conditionProcess.js
@@ -0,0 +1,21 @@
+import("system.vars");
+import("system.db");
+import("system.result");
+import("Sql_lib");
+
+var cond = SqlCondition.begin().andPrepareVars("AB_KEYWORD_ATTRIBUTE.CONTAINER", "$param.containerName_param");
+
+//filter for entries that are already used by entry_id
+var entryIdForFilter = vars.get("$param.filterAlreadyUsedByEntryId_param");
+if (entryIdForFilter)
+{
+    var exclusiveFilterCondition = SqlCondition.begin()
+        .andPrepare("AB_KEYWORD_ATTRIBUTERELATION.AB_KEYWORD_ENTRY_ID", entryIdForFilter)
+        .buildSql("AB_KEYWORD_ATTRIBUTE.AB_KEYWORD_ATTRIBUTEID not in (\n\
+            select AB_KEYWORD_ATTRIBUTERELATION.AB_KEYWORD_ATTRIBUTE_ID \n\
+            from AB_KEYWORD_ATTRIBUTERELATION ", null, ")");
+    cond.andAttachPrepared(exclusiveFilterCondition);
+}
+
+var condStr = db.translateCondition(cond.build("1 = 1"));
+result.string(condStr);
\ No newline at end of file
diff --git a/entity/KeywordAttribute_entity/recordcontainers/db/recordfieldmappings/type.displayvalue/expression.js b/entity/KeywordAttribute_entity/recordcontainers/db/recordfieldmappings/type.displayvalue/expression.js
new file mode 100644
index 0000000000000000000000000000000000000000..4095a1df3b895b7e6887f19e94e719a9ec8fbdb5
--- /dev/null
+++ b/entity/KeywordAttribute_entity/recordcontainers/db/recordfieldmappings/type.displayvalue/expression.js
@@ -0,0 +1,5 @@
+import("system.result");
+import("Keyword_lib");
+
+var sql = KeywordUtils.getResolvedTitleSqlPart($KeywordRegistry.get.KeywordAttributeType, "AB_KEYWORD_ATTRIBUTE.TYPE");
+result.string(sql);
diff --git a/entity/KeywordAttribute_entity/titleProcess.js b/entity/KeywordAttribute_entity/titleProcess.js
new file mode 100644
index 0000000000000000000000000000000000000000..28fd67de270b497ba718dd4e91766bd22936f67e
--- /dev/null
+++ b/entity/KeywordAttribute_entity/titleProcess.js
@@ -0,0 +1,4 @@
+import("system.vars");
+import("system.result");
+
+result.string(vars.get("$field.NAME"));
\ No newline at end of file
diff --git a/entity/KeywordEntry_entity/KeywordEntry_entity.aod b/entity/KeywordEntry_entity/KeywordEntry_entity.aod
index 3a56ca85eee2549a8d19fcbc686a15680453ddc6..6be1227f046be4e01d3026703d495f2859cfdf5c 100644
--- a/entity/KeywordEntry_entity/KeywordEntry_entity.aod
+++ b/entity/KeywordEntry_entity/KeywordEntry_entity.aod
@@ -226,11 +226,17 @@
           <fieldName>KeywordWarehouses</fieldName>
           <isConsumer v="false" />
         </entityDependency>
+        <entityDependency>
+          <name>403c40a4-f747-4e47-ad60-07334724d6fb</name>
+          <entityName>KeywordAttribute_entity</entityName>
+          <fieldName>KeywordKeywordAttributeTypes</fieldName>
+          <isConsumer v="false" />
+        </entityDependency>
       </dependencies>
       <children>
         <entityParameter>
-          <name>onlyActives</name>
-          <code>%aditoprj%/entity/KeywordEntry_entity/entityfields/specificcontainerkeywords/children/onlyactives/code.js</code>
+          <name>onlyActives_param</name>
+          <code>%aditoprj%/entity/KeywordEntry_entity/entityfields/specificcontainerkeywords/children/onlyactives_param/code.js</code>
           <expose v="true" />
         </entityParameter>
       </children>
@@ -240,12 +246,32 @@
       <valueProcess>%aditoprj%/entity/KeywordEntry_entity/entityfields/title_translated/valueProcess.js</valueProcess>
     </entityField>
     <entityParameter>
-      <name>onlyActives</name>
-      <code>%aditoprj%/entity/KeywordEntry_entity/entityfields/onlyactives/code.js</code>
+      <name>onlyActives_param</name>
+      <code>%aditoprj%/entity/KeywordEntry_entity/entityfields/onlyactives_param/code.js</code>
       <expose v="true" />
       <triggerRecalculation v="true" />
       <description>PARAMETER</description>
     </entityParameter>
+    <entityConsumer>
+      <name>KeywordAttributeRelations</name>
+      <title>Keyword Attribute Values</title>
+      <fieldType>DEPENDENCY_OUT</fieldType>
+      <dependency>
+        <name>dependency</name>
+        <entityName>KeywordAttributeRelation_entity</entityName>
+        <fieldName>SpecificContainer</fieldName>
+      </dependency>
+      <children>
+        <entityParameter>
+          <name>containerName_param</name>
+          <code>%aditoprj%/entity/KeywordEntry_entity/entityfields/keywordattributerelations/children/containername_param/code.js</code>
+        </entityParameter>
+        <entityParameter>
+          <name>keywordEntry_param</name>
+          <code>%aditoprj%/entity/KeywordEntry_entity/entityfields/keywordattributerelations/children/keywordentry_param/code.js</code>
+        </entityParameter>
+      </children>
+    </entityConsumer>
   </entityFields>
   <recordContainers>
     <dbRecordContainer>
diff --git a/entity/KeywordEntry_entity/entityfields/container/possibleItemsProcess.js b/entity/KeywordEntry_entity/entityfields/container/possibleItemsProcess.js
index 6d8037350d9404a9d3fda57b4f842a83a9f00e6e..50a930c3f4bcd04477c5c217fe2fb7c26294309e 100644
--- a/entity/KeywordEntry_entity/entityfields/container/possibleItemsProcess.js
+++ b/entity/KeywordEntry_entity/entityfields/container/possibleItemsProcess.js
@@ -1,6 +1,7 @@
 import("system.result");
-import("system.db");
+import("Keyword_lib");
 
-//TODO: move into UEM
-//first column is ID, second view value - which is the same because there is no ID for keyword-containers
-result.object(db.table("select distinct AB_KEYWORD_ENTRY.CONTAINER, AB_KEYWORD_ENTRY.CONTAINER from AB_KEYWORD_ENTRY order by 1 asc"));
\ No newline at end of file
+var res = KeywordUtils.getContainerNames().map(function(e){
+    return [e, e];//currently the first column is ID, second view value - which is the same because there is no ID for keyword-containers
+});
+result.object(res);
\ No newline at end of file
diff --git a/entity/KeywordEntry_entity/entityfields/keywordattributerelations/children/containername_param/code.js b/entity/KeywordEntry_entity/entityfields/keywordattributerelations/children/containername_param/code.js
new file mode 100644
index 0000000000000000000000000000000000000000..caec90defa83306ebcaa49f35ec771a94a722029
--- /dev/null
+++ b/entity/KeywordEntry_entity/entityfields/keywordattributerelations/children/containername_param/code.js
@@ -0,0 +1,4 @@
+import("system.vars");
+import("system.result");
+
+result.string(vars.get("$field.CONTAINER"));
\ No newline at end of file
diff --git a/entity/KeywordEntry_entity/entityfields/keywordattributerelations/children/keywordentry_param/code.js b/entity/KeywordEntry_entity/entityfields/keywordattributerelations/children/keywordentry_param/code.js
new file mode 100644
index 0000000000000000000000000000000000000000..53afbdfbbfe9044ca0a5af0984365d6b2ee5bdba
--- /dev/null
+++ b/entity/KeywordEntry_entity/entityfields/keywordattributerelations/children/keywordentry_param/code.js
@@ -0,0 +1,4 @@
+import("system.vars");
+import("system.result");
+
+result.string(vars.get("$field.AB_KEYWORD_ENTRYID"));
\ No newline at end of file
diff --git a/entity/KeywordEntry_entity/entityfields/onlyactives/code.js b/entity/KeywordEntry_entity/entityfields/onlyactives_param/code.js
similarity index 100%
rename from entity/KeywordEntry_entity/entityfields/onlyactives/code.js
rename to entity/KeywordEntry_entity/entityfields/onlyactives_param/code.js
diff --git a/entity/KeywordEntry_entity/entityfields/specificcontainerkeywords/children/onlyactives/code.js b/entity/KeywordEntry_entity/entityfields/specificcontainerkeywords/children/onlyactives_param/code.js
similarity index 100%
rename from entity/KeywordEntry_entity/entityfields/specificcontainerkeywords/children/onlyactives/code.js
rename to entity/KeywordEntry_entity/entityfields/specificcontainerkeywords/children/onlyactives_param/code.js
diff --git a/entity/KeywordEntry_entity/recordcontainers/db/conditionProcess.js b/entity/KeywordEntry_entity/recordcontainers/db/conditionProcess.js
index 7b0650f1d331e6ff462876ffdb803d67d58c9408..6be8b4e13cba7c2c1d210d3acd6e8c0b6dca61fd 100644
--- a/entity/KeywordEntry_entity/recordcontainers/db/conditionProcess.js
+++ b/entity/KeywordEntry_entity/recordcontainers/db/conditionProcess.js
@@ -5,7 +5,7 @@ import("Sql_lib");
 
 var cond = SqlCondition.begin().andPrepareVars("AB_KEYWORD_ENTRY.CONTAINER", "$param.containerName_param");
 
-if (vars.get("$param.onlyActives") == "true")
+if (vars.get("$param.onlyActives_param") == "true")
 {
     cond.andPrepare("AB_KEYWORD_ENTRY.ISACTIVE", "1");
 }
diff --git a/entity/Offer_entity/entityfields/probability/possibleItemsProcess.js b/entity/Offer_entity/entityfields/probability/possibleItemsProcess.js
index 12f66fd002f51eef98f0f2e7d2728eddabd19188..55d36f4786075593f83630cf383ec487af234902 100644
--- a/entity/Offer_entity/entityfields/probability/possibleItemsProcess.js
+++ b/entity/Offer_entity/entityfields/probability/possibleItemsProcess.js
@@ -1,4 +1,4 @@
 import("system.result");
 import("Keyword_lib");
 
-result.object(KeywordUtils.getStandardArray("OFFER.PROBABILITY"));
\ No newline at end of file
+result.object(LegacyKeywordUtils.getStandardArray("OFFER.PROBABILITY"));
\ No newline at end of file
diff --git a/entity/Organisation_entity/entityfields/price_politics/possibleItemsProcess.js b/entity/Organisation_entity/entityfields/price_politics/possibleItemsProcess.js
index 4e1c101c2a554e4e4b5e3499c4eb22f66fb7006e..0a795d357bbf1bcc88dbfebb8d15491e6ee68f65 100644
--- a/entity/Organisation_entity/entityfields/price_politics/possibleItemsProcess.js
+++ b/entity/Organisation_entity/entityfields/price_politics/possibleItemsProcess.js
@@ -1,4 +1,4 @@
 import("system.result");
 import("Keyword_lib");
 
-result.object(KeywordUtils.getStandardArray("SALESPROJECT.PRICE_POLITICS"));
\ No newline at end of file
+result.object(LegacyKeywordUtils.getStandardArray("SALESPROJECT.PRICE_POLITICS"));
\ No newline at end of file
diff --git a/entity/Organisation_entity/entityfields/strength/possibleItemsProcess.js b/entity/Organisation_entity/entityfields/strength/possibleItemsProcess.js
index ecb086cea25cb020523d5ffde7c10f6ef84ee40e..75aef701340c5393390f3978613a76c95c72ee54 100644
--- a/entity/Organisation_entity/entityfields/strength/possibleItemsProcess.js
+++ b/entity/Organisation_entity/entityfields/strength/possibleItemsProcess.js
@@ -1,4 +1,4 @@
 import("system.result");
 import("Keyword_lib");
 
-result.object(KeywordUtils.getStandardArray("SALESPROJECT.STRENGTH"));
\ No newline at end of file
+result.object(LegacyKeywordUtils.getStandardArray("SALESPROJECT.STRENGTH"));
\ No newline at end of file
diff --git a/entity/Organisation_entity/entityfields/weakness/possibleItemsProcess.js b/entity/Organisation_entity/entityfields/weakness/possibleItemsProcess.js
index 0d46206dc218028d42e8d68b65412e3e0a8043de..cf8185dc33c44e8994ef345b06ca0c76cd5606dc 100644
--- a/entity/Organisation_entity/entityfields/weakness/possibleItemsProcess.js
+++ b/entity/Organisation_entity/entityfields/weakness/possibleItemsProcess.js
@@ -1,4 +1,4 @@
 import("system.result");
 import("Keyword_lib");
 
-result.object(KeywordUtils.getStandardArray("SALESPROJECT.WEAKNESS"));
\ No newline at end of file
+result.object(LegacyKeywordUtils.getStandardArray("SALESPROJECT.WEAKNESS"));
\ No newline at end of file
diff --git a/entity/SalesprojectClassificationEntry_entity/contentProcess.js b/entity/SalesprojectClassificationEntry_entity/contentProcess.js
index 438655ba1c6875566feca2d13471c202ed7fac65..42b3a22e85dab86208b6904cb55c363e03a4a2d0 100644
--- a/entity/SalesprojectClassificationEntry_entity/contentProcess.js
+++ b/entity/SalesprojectClassificationEntry_entity/contentProcess.js
@@ -16,7 +16,7 @@ if (vars.exists("$param.ClassId_param") && vars.exists("$param.SalesprojectId_pa
     if (classId && salesprojectId) {    
     
         // keywords which are part of the loaded class [[keyname, visibleName]]
-        entryKeywords = KeywordUtils.get("SALESPROJECT.CLASS", classId)[2].keywords;
+        entryKeywords = LegacyKeywordUtils.get("SALESPROJECT.CLASS", classId)[2].keywords;
 
         if (entryKeywords && classId && salesprojectId) {
             // correct db if kewords changed
@@ -38,7 +38,7 @@ if (vars.exists("$param.ClassId_param") && vars.exists("$param.SalesprojectId_pa
                     if (classifications[i][1] == entryKeyword[0]) {
                         // get points
                         if (classifications[i][2]) {
-                            points = KeywordUtils.get(entryKeyword[0], classifications[i][2])[2].points;
+                            points = LegacyKeywordUtils.get(entryKeyword[0], classifications[i][2])[2].points;
                         } else {
                             points = 0;
                         }
diff --git a/entity/SalesprojectClassificationEntry_entity/entityfields/value/possibleItemsProcess.js b/entity/SalesprojectClassificationEntry_entity/entityfields/value/possibleItemsProcess.js
index 9ea69e17d2d1150bfa5913991a7cd1999e87fc60..6662c114e028d7abd5084bd4c8526b178fbf7e64 100644
--- a/entity/SalesprojectClassificationEntry_entity/entityfields/value/possibleItemsProcess.js
+++ b/entity/SalesprojectClassificationEntry_entity/entityfields/value/possibleItemsProcess.js
@@ -5,5 +5,5 @@ import("Keyword_lib");
 
 var type = vars.get("$field.TYPE");
 if (type) {
-    result.object(KeywordUtils.getStandardArray(type));
+    result.object(LegacyKeywordUtils.getStandardArray(type));
 }
\ No newline at end of file
diff --git a/entity/SalesprojectClassificationEntry_entity/recordcontainers/jdito/contentProcess.js b/entity/SalesprojectClassificationEntry_entity/recordcontainers/jdito/contentProcess.js
index 720555512fcce825efa3ad8a1da2bda16e3cc9fb..e395e823ff44e911f43cc397496f3dc3bca2bb24 100644
--- a/entity/SalesprojectClassificationEntry_entity/recordcontainers/jdito/contentProcess.js
+++ b/entity/SalesprojectClassificationEntry_entity/recordcontainers/jdito/contentProcess.js
@@ -16,7 +16,7 @@ if (vars.exists("$param.ClassId_param") && vars.exists("$param.SalesprojectId_pa
     if (classId && salesprojectId) {    
     
         // keywords which are part of the loaded class [[keyname, visibleName]]
-        entryKeywords = KeywordUtils.get("SALESPROJECT.CLASS", classId)[2].keywords;
+        entryKeywords = LegacyKeywordUtils.get("SALESPROJECT.CLASS", classId)[2].keywords;
 
         if (entryKeywords && classId && salesprojectId) {
             // correct db if kewords changed
@@ -38,7 +38,7 @@ if (vars.exists("$param.ClassId_param") && vars.exists("$param.SalesprojectId_pa
                     if (classifications[i][1] == entryKeyword[0]) {
                         // get points
                         if (classifications[i][2]) {
-                            points = KeywordUtils.get(entryKeyword[0], classifications[i][2])[2].points;
+                            points = LegacyKeywordUtils.get(entryKeyword[0], classifications[i][2])[2].points;
                         } else {
                             points = 0;
                         }
diff --git a/entity/SalesprojectClassification_entity/contentProcess.js b/entity/SalesprojectClassification_entity/contentProcess.js
index f1676827b8aa6a7a1741b1bb44843ec46dd320ab..b6fad738b518935a48687e129f173a8fe1b4b495 100644
--- a/entity/SalesprojectClassification_entity/contentProcess.js
+++ b/entity/SalesprojectClassification_entity/contentProcess.js
@@ -3,7 +3,7 @@ import("system.logging");
 import("system.vars");
 import("Keyword_lib");
 
-var keyword = KeywordUtils.createKeyword("SALESPROJECT.CLASS");
+var keyword = LegacyKeywordUtils.createKeyword("SALESPROJECT.CLASS");
 
 if (vars.exists("$local.idvalues") && vars.get("$local.idvalues")) {
     var idValues = vars.get("$local.idvalues");
diff --git a/entity/SalesprojectClassification_entity/recordcontainers/jdito/contentProcess.js b/entity/SalesprojectClassification_entity/recordcontainers/jdito/contentProcess.js
index f1676827b8aa6a7a1741b1bb44843ec46dd320ab..b6fad738b518935a48687e129f173a8fe1b4b495 100644
--- a/entity/SalesprojectClassification_entity/recordcontainers/jdito/contentProcess.js
+++ b/entity/SalesprojectClassification_entity/recordcontainers/jdito/contentProcess.js
@@ -3,7 +3,7 @@ import("system.logging");
 import("system.vars");
 import("Keyword_lib");
 
-var keyword = KeywordUtils.createKeyword("SALESPROJECT.CLASS");
+var keyword = LegacyKeywordUtils.createKeyword("SALESPROJECT.CLASS");
 
 if (vars.exists("$local.idvalues") && vars.get("$local.idvalues")) {
     var idValues = vars.get("$local.idvalues");
diff --git a/entity/SalesprojectCompetition_entity/entityfields/org_price_politics/possibleItemsProcess.js b/entity/SalesprojectCompetition_entity/entityfields/org_price_politics/possibleItemsProcess.js
index 4e1c101c2a554e4e4b5e3499c4eb22f66fb7006e..0a795d357bbf1bcc88dbfebb8d15491e6ee68f65 100644
--- a/entity/SalesprojectCompetition_entity/entityfields/org_price_politics/possibleItemsProcess.js
+++ b/entity/SalesprojectCompetition_entity/entityfields/org_price_politics/possibleItemsProcess.js
@@ -1,4 +1,4 @@
 import("system.result");
 import("Keyword_lib");
 
-result.object(KeywordUtils.getStandardArray("SALESPROJECT.PRICE_POLITICS"));
\ No newline at end of file
+result.object(LegacyKeywordUtils.getStandardArray("SALESPROJECT.PRICE_POLITICS"));
\ No newline at end of file
diff --git a/entity/SalesprojectCompetition_entity/entityfields/org_strength/possibleItemsProcess.js b/entity/SalesprojectCompetition_entity/entityfields/org_strength/possibleItemsProcess.js
index ecb086cea25cb020523d5ffde7c10f6ef84ee40e..75aef701340c5393390f3978613a76c95c72ee54 100644
--- a/entity/SalesprojectCompetition_entity/entityfields/org_strength/possibleItemsProcess.js
+++ b/entity/SalesprojectCompetition_entity/entityfields/org_strength/possibleItemsProcess.js
@@ -1,4 +1,4 @@
 import("system.result");
 import("Keyword_lib");
 
-result.object(KeywordUtils.getStandardArray("SALESPROJECT.STRENGTH"));
\ No newline at end of file
+result.object(LegacyKeywordUtils.getStandardArray("SALESPROJECT.STRENGTH"));
\ No newline at end of file
diff --git a/entity/SalesprojectCompetition_entity/entityfields/org_weakness/possibleItemsProcess.js b/entity/SalesprojectCompetition_entity/entityfields/org_weakness/possibleItemsProcess.js
index 0d46206dc218028d42e8d68b65412e3e0a8043de..cf8185dc33c44e8994ef345b06ca0c76cd5606dc 100644
--- a/entity/SalesprojectCompetition_entity/entityfields/org_weakness/possibleItemsProcess.js
+++ b/entity/SalesprojectCompetition_entity/entityfields/org_weakness/possibleItemsProcess.js
@@ -1,4 +1,4 @@
 import("system.result");
 import("Keyword_lib");
 
-result.object(KeywordUtils.getStandardArray("SALESPROJECT.WEAKNESS"));
\ No newline at end of file
+result.object(LegacyKeywordUtils.getStandardArray("SALESPROJECT.WEAKNESS"));
\ No newline at end of file
diff --git a/entity/SalesprojectCompetition_entity/entityfields/phase/possibleItemsProcess.js b/entity/SalesprojectCompetition_entity/entityfields/phase/possibleItemsProcess.js
index 6b3cab17a088176400713fec1424da5b07116e70..b539741cfe61bd1df9f3a8de8496fe4d1b38ca76 100644
--- a/entity/SalesprojectCompetition_entity/entityfields/phase/possibleItemsProcess.js
+++ b/entity/SalesprojectCompetition_entity/entityfields/phase/possibleItemsProcess.js
@@ -1,4 +1,4 @@
-import("system.result");
-import("Keyword_lib");
-
-result.object(KeywordUtils.getStandardArray("SALESPROJECT.PHASE"));
\ No newline at end of file
+import("system.result");
+import("Keyword_lib");
+
+result.object(LegacyKeywordUtils.getStandardArray("SALESPROJECT.PHASE"));
\ No newline at end of file
diff --git a/entity/SalesprojectCompetition_entity/entityfields/status/possibleItemsProcess.js b/entity/SalesprojectCompetition_entity/entityfields/status/possibleItemsProcess.js
index 58995db12cd73edcc6934d3c2dd03ae26329f427..71e5ae0f7ba209331e370a4fa4099571f6c35667 100644
--- a/entity/SalesprojectCompetition_entity/entityfields/status/possibleItemsProcess.js
+++ b/entity/SalesprojectCompetition_entity/entityfields/status/possibleItemsProcess.js
@@ -1,4 +1,4 @@
 import("system.result");
 import("Keyword_lib");
 
-result.object(KeywordUtils.getStandardArray("SALESPROJECT.STATE"));
\ No newline at end of file
+result.object(LegacyKeywordUtils.getStandardArray("SALESPROJECT.STATE"));
\ No newline at end of file
diff --git a/entity/SalesprojectCycle_entity/entityfields/type/possibleItemsProcess.js b/entity/SalesprojectCycle_entity/entityfields/type/possibleItemsProcess.js
index e6aa09f49925845d789231c634ef54264ee95674..effac991d6646dd9c7969dedb551820331abebf9 100644
--- a/entity/SalesprojectCycle_entity/entityfields/type/possibleItemsProcess.js
+++ b/entity/SalesprojectCycle_entity/entityfields/type/possibleItemsProcess.js
@@ -2,5 +2,5 @@ import("system.result");
 import("system.vars");
 import("Keyword_lib");
 
-var items = KeywordUtils.getStandardArray("SALESPROJECT.CYCLE.TYPE");
+var items = LegacyKeywordUtils.getStandardArray("SALESPROJECT.CYCLE.TYPE");
 result.object(items);
\ No newline at end of file
diff --git a/entity/SalesprojectCycle_entity/entityfields/value/possibleItemsProcess.js b/entity/SalesprojectCycle_entity/entityfields/value/possibleItemsProcess.js
index 43fe214e3317823dd707f4381e16ed008c972b78..512b10f2cc7f884a6d5a532ce0223ad938e8fcb0 100644
--- a/entity/SalesprojectCycle_entity/entityfields/value/possibleItemsProcess.js
+++ b/entity/SalesprojectCycle_entity/entityfields/value/possibleItemsProcess.js
@@ -10,10 +10,10 @@ type = vars.getString("$field.TYPE");
 
 // load the possible values based on the type.
 if (type) {
-    keyword = KeywordUtils.get("SALESPROJECT.CYCLE.TYPE", type)[2].keyword;
+    keyword = LegacyKeywordUtils.get("SALESPROJECT.CYCLE.TYPE", type)[2].keyword;
         
     if (keyword) {
-        items = KeywordUtils.getStandardArray(keyword);
+        items = LegacyKeywordUtils.getStandardArray(keyword);
     }
 }
 
diff --git a/entity/Salesproject_entity/entityfields/estimation/possibleItemsProcess.js b/entity/Salesproject_entity/entityfields/estimation/possibleItemsProcess.js
index c87db915b8988b7e083a0515e10a08ff235b9601..f527f159dc20b1e2bf4dc0bb00bd2a028195169e 100644
--- a/entity/Salesproject_entity/entityfields/estimation/possibleItemsProcess.js
+++ b/entity/Salesproject_entity/entityfields/estimation/possibleItemsProcess.js
@@ -3,5 +3,5 @@ import("Keyword_lib");
 
 var items;
 
-items = KeywordUtils.getStandardArray("SALESPROJECT.ESTIMATION");
+items = LegacyKeywordUtils.getStandardArray("SALESPROJECT.ESTIMATION");
 result.object(items);
\ No newline at end of file
diff --git a/entity/Salesproject_entity/entityfields/image/valueProcess.js b/entity/Salesproject_entity/entityfields/image/valueProcess.js
index 44577344738dcc96fffc4ab230fd752abcfadd83..90f0619c9f05b2c4862a7b0c93e15648467ac16f 100644
--- a/entity/Salesproject_entity/entityfields/image/valueProcess.js
+++ b/entity/Salesproject_entity/entityfields/image/valueProcess.js
@@ -1,5 +1,5 @@
-import("system.vars");
-import("system.result");
-import("Keyword_lib");
-
-result.string("TEXT:" + KeywordUtils.getViewValue("SALESPROJECT.STATE", vars.getString("$field.STATE")) );
\ No newline at end of file
+import("system.vars");
+import("system.result");
+import("Keyword_lib");
+
+result.string("TEXT:" + LegacyKeywordUtils.getViewValue("SALESPROJECT.STATE", vars.getString("$field.STATE")) );
\ No newline at end of file
diff --git a/entity/Salesproject_entity/entityfields/phase/possibleItemsProcess.js b/entity/Salesproject_entity/entityfields/phase/possibleItemsProcess.js
index fcb07176fb9d188e414146908f117a226dd4b454..b539741cfe61bd1df9f3a8de8496fe4d1b38ca76 100644
--- a/entity/Salesproject_entity/entityfields/phase/possibleItemsProcess.js
+++ b/entity/Salesproject_entity/entityfields/phase/possibleItemsProcess.js
@@ -1,4 +1,4 @@
 import("system.result");
 import("Keyword_lib");
 
-result.object(KeywordUtils.getStandardArray("SALESPROJECT.PHASE"));
\ No newline at end of file
+result.object(LegacyKeywordUtils.getStandardArray("SALESPROJECT.PHASE"));
\ No newline at end of file
diff --git a/entity/Salesproject_entity/entityfields/probability/possibleItemsProcess.js b/entity/Salesproject_entity/entityfields/probability/possibleItemsProcess.js
index 69979090d87a0c3149a65fd7ceeb751addee4ec4..bea9f367e4a778352426678a9ef9ad69ced0ed5a 100644
--- a/entity/Salesproject_entity/entityfields/probability/possibleItemsProcess.js
+++ b/entity/Salesproject_entity/entityfields/probability/possibleItemsProcess.js
@@ -1,4 +1,4 @@
 import("system.result");
 import("Keyword_lib");
 
-result.object(KeywordUtils.getStandardArray("SALESPROJECT.PROBABILITY"));
\ No newline at end of file
+result.object(LegacyKeywordUtils.getStandardArray("SALESPROJECT.PROBABILITY"));
\ No newline at end of file
diff --git a/entity/Salesproject_entity/entityfields/state/possibleItemsProcess.js b/entity/Salesproject_entity/entityfields/state/possibleItemsProcess.js
index ab6d2ec06bfc317fd578c0d9d20efb04fe3a1e70..904fa16280fd9e6516caf2915c795214425359f6 100644
--- a/entity/Salesproject_entity/entityfields/state/possibleItemsProcess.js
+++ b/entity/Salesproject_entity/entityfields/state/possibleItemsProcess.js
@@ -3,5 +3,5 @@ import("Keyword_lib");
 
 var items;
 
-items = KeywordUtils.getStandardArray("SALESPROJECT.STATE");
+items = LegacyKeywordUtils.getStandardArray("SALESPROJECT.STATE");
 result.object(items);
\ No newline at end of file
diff --git a/entity/Task_entity/entityfields/priority/possibleItemsProcess.js b/entity/Task_entity/entityfields/priority/possibleItemsProcess.js
index 745b8655027dd65e8f516cfa9f7b2e75cdaffc8a..83efeb09de4c609ecb59a10dc06c464bc380a859 100644
--- a/entity/Task_entity/entityfields/priority/possibleItemsProcess.js
+++ b/entity/Task_entity/entityfields/priority/possibleItemsProcess.js
@@ -3,5 +3,5 @@ import("Keyword_lib");
 
 var items;
 
-items = KeywordUtils.getStandardArray("TASK.PRIORITY");
+items = LegacyKeywordUtils.getStandardArray("TASK.PRIORITY");
 result.object(items);
\ No newline at end of file
diff --git a/entity/Task_entity/iconIdProcess.js b/entity/Task_entity/iconIdProcess.js
index d65e648d41234d7bdcc0620e3afd1cce86bd16ae..446b9205ba8168cddc02ac6dc0e96b7418361417 100644
--- a/entity/Task_entity/iconIdProcess.js
+++ b/entity/Task_entity/iconIdProcess.js
@@ -4,7 +4,7 @@ import("system.neon");
 import("Keyword_lib");
 
 var category = vars.getString("$field.PRIORITY");
-var kwd = KeywordUtils.createKeyword("TASK.PRIORITY");
+var kwd = LegacyKeywordUtils.createKeyword("TASK.PRIORITY");
 var icon = kwd.getPropForKey(category, "defaultAvatarRepresentation", true);
 
 result.string(icon || "VAADIN:TASKS");
\ No newline at end of file
diff --git a/neonContext/KeywordAttributeRelation_context/KeywordAttributeRelation_context.aod b/neonContext/KeywordAttributeRelation_context/KeywordAttributeRelation_context.aod
new file mode 100644
index 0000000000000000000000000000000000000000..196b3da70093e4871c522020c21389852cebeb53
--- /dev/null
+++ b/neonContext/KeywordAttributeRelation_context/KeywordAttributeRelation_context.aod
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<neonContext xmlns="http://www.adito.de/2018/ao/Model" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" VERSION="1.0.0" xsi:schemaLocation="http://www.adito.de/2018/ao/Model adito://models/xsd/neonContext/1.0.0">
+  <name>KeywordAttributeRelation_context</name>
+  <title>Keyword Attribute Values</title>
+  <majorModelMode>DISTRIBUTED</majorModelMode>
+  <entity>KeywordAttributeRelation_entity</entity>
+  <references>
+    <neonViewReference>
+      <name>4340ec15-39bd-4c0c-a7b9-c03829f9ff78</name>
+      <view>KeywordAttributeRelationRows_view</view>
+    </neonViewReference>
+  </references>
+</neonContext>
diff --git a/neonContext/KeywordAttribute_context/KeywordAttribute_context.aod b/neonContext/KeywordAttribute_context/KeywordAttribute_context.aod
new file mode 100644
index 0000000000000000000000000000000000000000..9b507f230bc3b86f25daa8f9da9f665131a26aad
--- /dev/null
+++ b/neonContext/KeywordAttribute_context/KeywordAttribute_context.aod
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<neonContext xmlns="http://www.adito.de/2018/ao/Model" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" VERSION="1.0.0" xsi:schemaLocation="http://www.adito.de/2018/ao/Model adito://models/xsd/neonContext/1.0.0">
+  <name>KeywordAttribute_context</name>
+  <title>Keyword Attribute</title>
+  <majorModelMode>DISTRIBUTED</majorModelMode>
+  <filterview>KeywordAttributeFilter_view</filterview>
+  <editview>KeywordAttributeEdit_view</editview>
+  <entity>KeywordAttribute_entity</entity>
+  <references>
+    <neonViewReference>
+      <name>3d33f7a2-f215-4810-bb70-adaae32e09f9</name>
+      <view>KeywordAttributeFilter_view</view>
+    </neonViewReference>
+    <neonViewReference>
+      <name>ca209089-0c98-4424-9e15-4e3c01b0e2aa</name>
+      <view>KeywordAttributeEdit_view</view>
+    </neonViewReference>
+  </references>
+</neonContext>
diff --git a/neonContext/Keyword_context/Keyword_context.aod b/neonContext/KeywordEntry_context/KeywordEntry_context.aod
similarity index 61%
rename from neonContext/Keyword_context/Keyword_context.aod
rename to neonContext/KeywordEntry_context/KeywordEntry_context.aod
index 17b405b6d08e222a5c937f9dcf9a81ff30b98413..f5d5789f35ff1e4541fe7991dd104808d63f11d9 100644
--- a/neonContext/Keyword_context/Keyword_context.aod
+++ b/neonContext/KeywordEntry_context/KeywordEntry_context.aod
@@ -1,25 +1,30 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <neonContext xmlns="http://www.adito.de/2018/ao/Model" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" VERSION="1.0.0" xsi:schemaLocation="http://www.adito.de/2018/ao/Model adito://models/xsd/neonContext/1.0.0">
-  <name>Keyword_context</name>
+  <name>KeywordEntry_context</name>
   <title>Keyword</title>
   <description>&amp;lt;null value&amp;gt;</description>
   <majorModelMode>DISTRIBUTED</majorModelMode>
-  <filterview>KeywordFilter_view</filterview>
-  <editview>KeywordEdit_view</editview>
-  <preview>KeywordPreview_view</preview>
+  <mainview>KeywordEntryMain_view</mainview>
+  <filterview>KeywordEntryFilter_view</filterview>
+  <editview>KeywordEntryEdit_view</editview>
+  <preview>KeywordEntryPreview_view</preview>
   <entity>KeywordEntry_entity</entity>
   <references>
     <neonViewReference>
       <name>75271eb0-8ddf-4b02-a943-01f589df1b20</name>
-      <view>KeywordFilter_view</view>
+      <view>KeywordEntryFilter_view</view>
     </neonViewReference>
     <neonViewReference>
       <name>e73f8fa3-3538-4af5-8116-84358b3254fa</name>
-      <view>KeywordEdit_view</view>
+      <view>KeywordEntryEdit_view</view>
     </neonViewReference>
     <neonViewReference>
       <name>9bb352b9-5a8c-41ac-9c42-7f4f7f4827f3</name>
-      <view>KeywordPreview_view</view>
+      <view>KeywordEntryPreview_view</view>
+    </neonViewReference>
+    <neonViewReference>
+      <name>bba3520e-3e12-44e9-89dc-b42183e332ec</name>
+      <view>KeywordEntryMain_view</view>
     </neonViewReference>
   </references>
 </neonContext>
diff --git a/neonView/KeywordAttributeEdit_view/KeywordAttributeEdit_view.aod b/neonView/KeywordAttributeEdit_view/KeywordAttributeEdit_view.aod
new file mode 100644
index 0000000000000000000000000000000000000000..69c0e3fca07a06e8c913995bd618eb19b3e88465
--- /dev/null
+++ b/neonView/KeywordAttributeEdit_view/KeywordAttributeEdit_view.aod
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<neonView xmlns="http://www.adito.de/2018/ao/Model" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" VERSION="1.0.1" xsi:schemaLocation="http://www.adito.de/2018/ao/Model adito://models/xsd/neonView/1.0.1">
+  <name>KeywordAttributeEdit_view</name>
+  <majorModelMode>DISTRIBUTED</majorModelMode>
+  <layout>
+    <boxLayout>
+      <name>layout</name>
+    </boxLayout>
+  </layout>
+  <children>
+    <genericViewTemplate>
+      <name>mainGeneric</name>
+      <editMode v="true" />
+      <entityField>#ENTITY</entityField>
+      <fields>
+        <entityFieldLink>
+          <name>88fcd6c8-8dfc-4a1d-96d9-33412768feb9</name>
+          <entityField>CONTAINER</entityField>
+        </entityFieldLink>
+        <entityFieldLink>
+          <name>4e120b1d-1016-41a1-abe7-9d28f8053380</name>
+          <entityField>NAME</entityField>
+        </entityFieldLink>
+        <entityFieldLink>
+          <name>245c3f6f-3874-46d6-a24d-72cb9abb2e16</name>
+          <entityField>TYPE</entityField>
+        </entityFieldLink>
+      </fields>
+    </genericViewTemplate>
+  </children>
+</neonView>
diff --git a/neonView/KeywordAttributeFilter_view/KeywordAttributeFilter_view.aod b/neonView/KeywordAttributeFilter_view/KeywordAttributeFilter_view.aod
new file mode 100644
index 0000000000000000000000000000000000000000..58405b852717bfc66e9c1c5d4217268684ca5823
--- /dev/null
+++ b/neonView/KeywordAttributeFilter_view/KeywordAttributeFilter_view.aod
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<neonView xmlns="http://www.adito.de/2018/ao/Model" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" VERSION="1.0.1" xsi:schemaLocation="http://www.adito.de/2018/ao/Model adito://models/xsd/neonView/1.0.1">
+  <name>KeywordAttributeFilter_view</name>
+  <majorModelMode>DISTRIBUTED</majorModelMode>
+  <filterable v="true" />
+  <layout>
+    <boxLayout>
+      <name>layout</name>
+    </boxLayout>
+  </layout>
+  <children>
+    <tableViewTemplate>
+      <name>table</name>
+      <autoNewRow v="true" />
+      <entityField>#ENTITY</entityField>
+      <columns>
+        <neonTableColumn>
+          <name>94fdd272-46f0-415e-aff8-76789a215921</name>
+          <entityField>#ICON</entityField>
+        </neonTableColumn>
+        <neonTableColumn>
+          <name>682fd08f-b121-469c-b86e-afdf013dbc7b</name>
+          <entityField>NAME</entityField>
+        </neonTableColumn>
+        <neonTableColumn>
+          <name>8d142e4d-c15d-409a-9a2c-251192e3e98e</name>
+          <entityField>TYPE</entityField>
+        </neonTableColumn>
+        <neonTableColumn>
+          <name>7efe2ae9-8b76-439f-95cb-547f7dec9057</name>
+          <entityField>CONTAINER</entityField>
+        </neonTableColumn>
+      </columns>
+    </tableViewTemplate>
+  </children>
+</neonView>
diff --git a/neonView/KeywordAttributeRelationRows_view/KeywordAttributeRelationRows_view.aod b/neonView/KeywordAttributeRelationRows_view/KeywordAttributeRelationRows_view.aod
new file mode 100644
index 0000000000000000000000000000000000000000..93dff9fcdd7d70394716c779190074baa2eb8e5d
--- /dev/null
+++ b/neonView/KeywordAttributeRelationRows_view/KeywordAttributeRelationRows_view.aod
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<neonView xmlns="http://www.adito.de/2018/ao/Model" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" VERSION="1.0.1" xsi:schemaLocation="http://www.adito.de/2018/ao/Model adito://models/xsd/neonView/1.0.1">
+  <name>KeywordAttributeRelationRows_view</name>
+  <majorModelMode>DISTRIBUTED</majorModelMode>
+  <filterable v="false" />
+  <layout>
+    <boxLayout>
+      <name>layout</name>
+    </boxLayout>
+  </layout>
+  <children>
+    <tableViewTemplate>
+      <name>main</name>
+      <autoNewRow v="true" />
+      <entityField>#ENTITY</entityField>
+      <columns>
+        <neonTableColumn>
+          <name>f0eec86d-a223-4208-9e9d-6a6bda1969c8</name>
+          <entityField>AB_KEYWORD_ATTRIBUTE_ID</entityField>
+        </neonTableColumn>
+        <neonTableColumn>
+          <name>04d24334-3b82-4193-b289-6a96f640e521</name>
+          <entityField>CHAR_VALUE</entityField>
+        </neonTableColumn>
+      </columns>
+    </tableViewTemplate>
+  </children>
+</neonView>
diff --git a/neonView/KeywordEdit_view/KeywordEdit_view.aod b/neonView/KeywordEntryEdit_view/KeywordEntryEdit_view.aod
similarity index 96%
rename from neonView/KeywordEdit_view/KeywordEdit_view.aod
rename to neonView/KeywordEntryEdit_view/KeywordEntryEdit_view.aod
index 3275db9f41f66eda6375dc1c90da459abbcfe8f0..5f5e927e380c67da92e94afdfd8fc7d498bf3aba 100644
--- a/neonView/KeywordEdit_view/KeywordEdit_view.aod
+++ b/neonView/KeywordEntryEdit_view/KeywordEntryEdit_view.aod
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <neonView xmlns="http://www.adito.de/2018/ao/Model" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" VERSION="1.0.1" xsi:schemaLocation="http://www.adito.de/2018/ao/Model adito://models/xsd/neonView/1.0.1">
-  <name>KeywordEdit_view</name>
+  <name>KeywordEntryEdit_view</name>
   <majorModelMode>DISTRIBUTED</majorModelMode>
   <layout>
     <boxLayout>
diff --git a/neonView/KeywordFilter_view/KeywordFilter_view.aod b/neonView/KeywordEntryFilter_view/KeywordEntryFilter_view.aod
similarity index 97%
rename from neonView/KeywordFilter_view/KeywordFilter_view.aod
rename to neonView/KeywordEntryFilter_view/KeywordEntryFilter_view.aod
index c69a8a6af1adb1ba60271b77064ec3fbc12b87b5..37211f010c065d375041efbf7123f747fb4f9199 100644
--- a/neonView/KeywordFilter_view/KeywordFilter_view.aod
+++ b/neonView/KeywordEntryFilter_view/KeywordEntryFilter_view.aod
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <neonView xmlns="http://www.adito.de/2018/ao/Model" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" VERSION="1.0.1" xsi:schemaLocation="http://www.adito.de/2018/ao/Model adito://models/xsd/neonView/1.0.1">
-  <name>KeywordFilter_view</name>
+  <name>KeywordEntryFilter_view</name>
   <majorModelMode>DISTRIBUTED</majorModelMode>
   <filterable v="true" />
   <layout>
diff --git a/neonView/KeywordEntryMain_view/KeywordEntryMain_view.aod b/neonView/KeywordEntryMain_view/KeywordEntryMain_view.aod
new file mode 100644
index 0000000000000000000000000000000000000000..fa78883ff276bb9989f9eeef0f00c912313bba40
--- /dev/null
+++ b/neonView/KeywordEntryMain_view/KeywordEntryMain_view.aod
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<neonView xmlns="http://www.adito.de/2018/ao/Model" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" VERSION="1.0.1" xsi:schemaLocation="http://www.adito.de/2018/ao/Model adito://models/xsd/neonView/1.0.1">
+  <name>KeywordEntryMain_view</name>
+  <majorModelMode>DISTRIBUTED</majorModelMode>
+  <layout>
+    <masterSlaveLayout>
+      <name>layout</name>
+      <master>19d059ec-7b77-4662-ad0b-14f43c76272e</master>
+    </masterSlaveLayout>
+  </layout>
+  <children>
+    <neonViewReference>
+      <name>19d059ec-7b77-4662-ad0b-14f43c76272e</name>
+      <entityField>#ENTITY</entityField>
+      <view>KeywordEntryPreview_view</view>
+    </neonViewReference>
+    <neonViewReference>
+      <name>e722eb4b-5737-4801-b6e4-550fca43963a</name>
+      <entityField>KeywordAttributeRelations</entityField>
+      <view>KeywordAttributeRelationRows_view</view>
+    </neonViewReference>
+  </children>
+</neonView>
diff --git a/neonView/KeywordPreview_view/KeywordPreview_view.aod b/neonView/KeywordEntryPreview_view/KeywordEntryPreview_view.aod
similarity index 97%
rename from neonView/KeywordPreview_view/KeywordPreview_view.aod
rename to neonView/KeywordEntryPreview_view/KeywordEntryPreview_view.aod
index 0dc50a66f5d5af36af64cb1bee37f598c8b2832d..81e59a0f9d9be3cf73f77d9e3d592d99ef53989b 100644
--- a/neonView/KeywordPreview_view/KeywordPreview_view.aod
+++ b/neonView/KeywordEntryPreview_view/KeywordEntryPreview_view.aod
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <neonView xmlns="http://www.adito.de/2018/ao/Model" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" VERSION="1.0.1" xsi:schemaLocation="http://www.adito.de/2018/ao/Model adito://models/xsd/neonView/1.0.1">
-  <name>KeywordPreview_view</name>
+  <name>KeywordEntryPreview_view</name>
   <majorModelMode>DISTRIBUTED</majorModelMode>
   <layout>
     <boxLayout>
diff --git a/others/db_changes/data_alias/data/AditoBasic/ab_keyword_entry.xml b/others/db_changes/data_alias/data/AditoBasic/ab_keyword_entry.xml
index 2110a2debc17887b01cbf168b76483aa5b027205..75f8991f77e2a93ea463d83a66d3e15fb196306e 100644
--- a/others/db_changes/data_alias/data/AditoBasic/ab_keyword_entry.xml
+++ b/others/db_changes/data_alias/data/AditoBasic/ab_keyword_entry.xml
@@ -22,4 +22,5 @@
     <include relativeToChangelogFile="true" file="ab_keyword_entry/init_StockWarehouse.xml"/>
     <include relativeToChangelogFile="true" file="ab_keyword_entry/init_TaskStatus.xml"/>
     <include relativeToChangelogFile="true" file="ab_keyword_entry/init_TaskType.xml"/>
+    <include relativeToChangelogFile="true" file="ab_keyword_entry/init_KeywordAttributeType.xml"/>
 </databaseChangeLog>
diff --git a/others/db_changes/data_alias/data/AditoBasic/ab_keyword_entry/init_KeywordAttributeType.xml b/others/db_changes/data_alias/data/AditoBasic/ab_keyword_entry/init_KeywordAttributeType.xml
new file mode 100644
index 0000000000000000000000000000000000000000..a58e5e8e3cffea3dc74a4b43afde6e38370d0589
--- /dev/null
+++ b/others/db_changes/data_alias/data/AditoBasic/ab_keyword_entry/init_KeywordAttributeType.xml
@@ -0,0 +1,52 @@
+<?xml version="1.1" encoding="UTF-8" standalone="no"?>
+<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.6.xsd">
+  <changeSet author="j.goderbauer" id="31959cda-46f5-443e-b90b-499009895453">
+    <insert tableName="AB_KEYWORD_ENTRY">
+      <column name="AB_KEYWORD_ENTRYID" value="6fea53cc-c167-4aad-9468-64a0c525ad47"/>
+      <column name="KEYID" value="BOOL_VALUE"/>
+      <column name="TITLE" value="Boolean value"/>
+      <column name="CONTAINER" value="KeywordAttributeType"/>
+      <column name="SORTING" valueNumeric="0"/>
+      <column name="ISACTIVE" valueNumeric="1"/>
+      <column name="ISESSENTIAL" valueNumeric="1"/>
+    </insert>
+    <insert tableName="AB_KEYWORD_ENTRY">
+      <column name="AB_KEYWORD_ENTRYID" value="93c67ca9-dec2-4d8a-863a-3b9cbce7bed1"/>
+      <column name="KEYID" value="CHAR_VALUE"/>
+      <column name="TITLE" value="String value"/>
+      <column name="CONTAINER" value="KeywordAttributeType"/>
+      <column name="SORTING" valueNumeric="1"/>
+      <column name="ISACTIVE" valueNumeric="1"/>
+      <column name="ISESSENTIAL" valueNumeric="1"/>
+    </insert>
+    <insert tableName="AB_KEYWORD_ENTRY">
+      <column name="AB_KEYWORD_ENTRYID" value="f6566efc-5918-426d-9a45-a160ad632d55"/>
+      <column name="KEYID" value="NUMBER_VALUE"/>
+      <column name="TITLE" value="Numeric value"/>
+      <column name="CONTAINER" value="KeywordAttributeType"/>
+      <column name="SORTING" valueNumeric="2"/>
+      <column name="ISACTIVE" valueNumeric="1"/>
+      <column name="ISESSENTIAL" valueNumeric="1"/>
+    </insert>
+    <rollback>
+      <delete tableName="AB_KEYWORD_ENTRY">
+        <where>AB_KEYWORD_ENTRYID = ?</where>
+        <whereParams>
+          <param value="6fea53cc-c167-4aad-9468-64a0c525ad47"/>
+        </whereParams>
+      </delete>
+      <delete tableName="AB_KEYWORD_ENTRY">
+        <where>AB_KEYWORD_ENTRYID = ?</where>
+        <whereParams>
+          <param value="93c67ca9-dec2-4d8a-863a-3b9cbce7bed1"/>
+        </whereParams>
+      </delete>
+      <delete tableName="AB_KEYWORD_ENTRY">
+        <where>AB_KEYWORD_ENTRYID = ?</where>
+        <whereParams>
+          <param value="f6566efc-5918-426d-9a45-a160ad632d55"/>
+        </whereParams>
+      </delete>
+    </rollback>
+  </changeSet>
+</databaseChangeLog>
\ No newline at end of file
diff --git a/others/db_changes/data_alias/struct/AditoBasic/create_ab_attribute.xml b/others/db_changes/data_alias/struct/AditoBasic/create_ab_attribute.xml
index fa88566e563760367449264e9c90bd3859a679ae..ff749c09fdc8d86a5b9b9b2b608dbe17640f9a39 100644
--- a/others/db_changes/data_alias/struct/AditoBasic/create_ab_attribute.xml
+++ b/others/db_changes/data_alias/struct/AditoBasic/create_ab_attribute.xml
@@ -7,7 +7,7 @@
             </column>
             <column name="ATTRIBUTE_PARENT_ID" type="CHAR(36)">
             </column>
-            <column name="ATTRIBUTE_TYPE" type="NVARCHAR(63)">
+            <column name="ATTRIBUTE_TYPE" type="CHAR(36)">
                 <constraints nullable="false"/>
             </column>
             <column name="ATTRIBUTE_NAME" type="NVARCHAR(63)">
diff --git a/process/Communication_lib/process.js b/process/Communication_lib/process.js
index e1c5313d9d54385391c0ad2b11e76f9833521856..1970ce342437f15c3260901f762c3aeca60bd27e 100644
--- a/process/Communication_lib/process.js
+++ b/process/Communication_lib/process.js
@@ -22,7 +22,7 @@ function CommUtil(){}
  */
 CommUtil.getMediumIdsByCategory = function (pCategory)
 {
-    var kwd = KeywordUtils.createKeyword("COMMUNICATION.MEDIUM");
+    var kwd = LegacyKeywordUtils.createKeyword("COMMUNICATION.MEDIUM");
     kwd.filter(function(id, name, customs){
         return customs.category == pCategory;
     });
diff --git a/process/Keyword_lib/process.js b/process/Keyword_lib/process.js
index ee4c7003fc352e0a41adf1d1b8ba2378d6dbf1d5..f35e876b6ea492b96bd9fa34cf254bcd0b2a9521 100644
--- a/process/Keyword_lib/process.js
+++ b/process/Keyword_lib/process.js
@@ -23,6 +23,7 @@ function $KeywordRegistry(){}
 
 //static property
 $KeywordRegistry.get = {
+    KeywordAttributeType: "KeywordAttributeType",
     ContractPayment: "ContractPayment",
     ContractStatus: "ContractStatus",
     ContractType: "ContractType",
@@ -71,6 +72,47 @@ KeywordUtils.getResolvedTitleSqlPart = function(pContainerName, pDbFieldName, pL
     return db.translateStatement(resSql);
 };
 
+/**
+ * returns a specific name (translated) - this is normally the view-value - of a given keyword;
+ * <br/>if the key could not be found an empty string "" is returned 
+ * @param {String} keywordType specifies the type of the keyword and therefore the list elements; e.g. "COUNTRY"
+ * @param {String} key id value of the keyword where the view-value shall be searched
+ * @return {String} representation of the translated name of the keyword-key
+ * @example
+ * var histMedium;
+ * histMedium = vars.get("$field.MEDIUM");
+ * if (histMedium){
+ *     result.string(vars.get("$field.SUBJECT") + " (" + LegacyKeywordUtils.getViewValue("ACTIVITY.MEDIUM", histMedium) + ")");
+ * }
+ */
+KeywordUtils.getViewValue = function(keywordType, key)
+{
+    if (!$KeywordRegistry.get[keywordType])
+        return "";
+
+    var sql = SqlCondition.begin()
+                          .andPrepare("AB_KEYWORD_ENTRY.CONTAINER", keywordType)
+                          .andPrepare("AB_KEYWORD_ENTRY.KEYID", key)
+                          .buildSql("select AB_KEYWORD_ENTRY.TITLE from AB_KEYWORD_ENTRY");
+    var originalTitle = db.cell(sql);
+    if (originalTitle == "")
+        return "";
+    var translatedTitle = translate.text(originalTitle);
+    return translatedTitle;
+}
+
+/**
+* provides a distinctive list of all keyword-container-names in the system
+* 
+* @return {String[]} containerNames as 1D-Array
+*/
+KeywordUtils.getContainerNames = function()
+{
+    var list = db.array(db.COLUMN, "select distinct AB_KEYWORD_ENTRY.CONTAINER from AB_KEYWORD_ENTRY order by AB_KEYWORD_ENTRY.CONTAINER asc");
+    return list;
+};
+
+
 /**
  * provides methods for interactions with the sepcial-keywords "LANGUAGE"
  * 
@@ -93,6 +135,15 @@ LanguageKeywordUtils.getResolvedTitleSqlPart = function(pDbFieldName, pLocale)
     return db.translateStatement(resSql);
 };
 
+
+/**
+ * provides methods for interactions with legcy keywords
+ * @deprecated use instead the new meachanism via the KeywordUtils
+ * 
+ * @class
+ */
+function LegacyKeywordUtils(){}
+
 (function(){//scope for private functions
 
 
@@ -103,11 +154,11 @@ LanguageKeywordUtils.getResolvedTitleSqlPart = function(pDbFieldName, pLocale)
      * @example
      * var items;
      * 
-     * items = KeywordUtils.getStandardArray("ADDRESS.TYPE");
+     * items = LegacyKeywordUtils.getStandardArray("ADDRESS.TYPE");
      * result.object(items);
      */
-    KeywordUtils.getStandardArray = function(keywordType){
-        return KeywordUtils.createKeyword(keywordType).toArray(["id", "name"]);
+    LegacyKeywordUtils.getStandardArray = function(keywordType){
+        return LegacyKeywordUtils.createKeyword(keywordType).toArray(["id", "name"]);
     }
     
     /**
@@ -117,11 +168,11 @@ LanguageKeywordUtils.getResolvedTitleSqlPart = function(pDbFieldName, pLocale)
      * @example
      * var items;
      * 
-     * items = KeywordUtils.getStandardArray("ADDRESS.TYPE");
+     * items = LegacyKeywordUtils.getStandardArray("ADDRESS.TYPE");
      * result.object(items);
      */
-    KeywordUtils.getStandardArrayProps = function(keywordType){
-        return KeywordUtils.createKeyword(keywordType).toArray(["id", "name", "customProperties"]);
+    LegacyKeywordUtils.getStandardArrayProps = function(keywordType){
+        return LegacyKeywordUtils.createKeyword(keywordType).toArray(["id", "name", "customProperties"]);
     }
 
     /**
@@ -130,11 +181,11 @@ LanguageKeywordUtils.getResolvedTitleSqlPart = function(pDbFieldName, pLocale)
      * @param {String} key the key for the keyword ("1", "2", "3", etc.)
      * @return {Array} a 2D array in form of [["id1", "name1", properties1], ["idN", "nameN", propertiesN]]
      * @example
-     * var item = KeywordUtils.get("ADDRESS.TYPE", "1");
+     * var item = LegacyKeywordUtils.get("ADDRESS.TYPE", "1");
      * result.object(item);
      */
-    KeywordUtils.get = function(keywordType, key){
-        return KeywordUtils.createKeyword(keywordType).getPropsForKey(key, ["id", "name", "customProperties"]);
+    LegacyKeywordUtils.get = function(keywordType, key){
+        return LegacyKeywordUtils.createKeyword(keywordType).getPropsForKey(key, ["id", "name", "customProperties"]);
     }
     
     /**
@@ -147,34 +198,12 @@ LanguageKeywordUtils.getResolvedTitleSqlPart = function(pDbFieldName, pLocale)
      * var histMedium;
      * histMedium = vars.get("$field.MEDIUM");
      * if (histMedium){
-     *     result.string(vars.get("$field.SUBJECT") + " (" + KeywordUtils.getViewValue("ACTIVITY.MEDIUM", histMedium) + ")");
+     *     result.string(vars.get("$field.SUBJECT") + " (" + LegacyKeywordUtils.getViewValue("ACTIVITY.MEDIUM", histMedium) + ")");
      * }
      */
-    KeywordUtils.getViewValue = function(keywordType, key){
-        //temporary solution: support old (=legacy) and new keyword logic
-        if ($KeywordRegistry.get[keywordType])
-        {
-            //new keyword logic
-            /*select AB_KEYWORD_ENTRY.TITLE
-            from AB_KEYWORD_ENTRY
-            where AB_KEYWORD_ENTRY.CONTAINER = '' and KEYID = ''*/
-            var sql = SqlCondition.begin()
-                                   .andPrepare("AB_KEYWORD_ENTRY.CONTAINER", keywordType)
-                                   .andPrepare("AB_KEYWORD_ENTRY.KEYID", key)
-                                   .buildSql("select AB_KEYWORD_ENTRY.TITLE from AB_KEYWORD_ENTRY");
-            var originalTitle = db.cell(sql);
-            if (originalTitle == "")
-                return "";
-            
-            var translatedTitle = translate.text(originalTitle);
-            return translatedTitle;
-        }
-        else
-        {
-            //legacy keyword logic
-            var k = KeywordUtils.createKeyword(keywordType);
-            return k.getPropForKey(key, "name") || "";
-        }
+    LegacyKeywordUtils.getViewValue = function(keywordType, key){
+        var k = LegacyKeywordUtils.createKeyword(keywordType);
+        return k.getPropForKey(key, "name") || "";
     }
 
     /**
@@ -188,7 +217,7 @@ LanguageKeywordUtils.getResolvedTitleSqlPart = function(pDbFieldName, pLocale)
      * <br/>- getPropsForKey
      * <br/>- filter
      */
-    KeywordUtils.createKeyword = function(keywordType, translationLocale){
+    LegacyKeywordUtils.createKeyword = function(keywordType, translationLocale){
         var valueContainer, _toArrayFn, _getPropForKeyFn, _getPropsForKeyFn;
         
         var locale;
@@ -202,15 +231,6 @@ LanguageKeywordUtils.getResolvedTitleSqlPart = function(pDbFieldName, pLocale)
         }
 
         switch (keywordType){
-            case "COUNTRY":
-                valueContainer = _createKeywordEntriesContainer([
-                     _createKeywordEntry("DE", translate.text("Germany", locale))
-                    ,_createKeywordEntry("AT", translate.text("Austria", locale))
-                    ,_createKeywordEntry("CH", translate.text("Switzerland", locale))
-                    ,_createKeywordEntry("GB", translate.text("United Kingdom", locale))
-                    ,_createKeywordEntry("NO", translate.text("Norway", locale))
-                ]);
-                break;
             case "ACTIVITY.CATEGORY":
                 valueContainer = _createKeywordEntriesContainer([
                      _createKeywordEntry("0", translate.text("Visit", locale), null, {defaultAvatarRepresentation: "VAADIN:TRAIN"})
@@ -235,16 +255,6 @@ LanguageKeywordUtils.getResolvedTitleSqlPart = function(pDbFieldName, pLocale)
                     ,_createKeywordEntry("4", translate.text("Post office box", locale), null, {org: true, person: true})
                 ]);
                 break;
-            case "GROUPCODE":
-                valueContainer = _createKeywordEntriesContainer([
-                     _createKeywordEntry("1", translate.text("Commodity group 1", locale))
-                    ,_createKeywordEntry("2", translate.text("Commodity group 2", locale))
-                    ,_createKeywordEntry("3", translate.text("Commodity group 3", locale))
-                    ,_createKeywordEntry("4", translate.text("Discount", locale))
-                    ,_createKeywordEntry("5", translate.text("Spare parts", locale))
-                    ,_createKeywordEntry("6", translate.text("Service", locale))
-                ]);
-                break;
             case "SALESPROJECT.PRICE_POLITICS":
                 valueContainer = _createKeywordEntriesContainer([
                      _createKeywordEntry("1", translate.text("Abomodel", locale))
@@ -387,14 +397,6 @@ LanguageKeywordUtils.getResolvedTitleSqlPart = function(pDbFieldName, pLocale)
                     ,_createKeywordEntry("5", translate.text("100 %", locale), null, {percentValue: 100})
                 ]);
                 break;
-            case "SALESORDER.STATUS":
-                valueContainer = _createKeywordEntriesContainer([
-                     _createKeywordEntry("1", translate.text("Checked", locale))
-                    ,_createKeywordEntry("2", translate.text("Sent", locale))
-                    ,_createKeywordEntry("3", translate.text("Won", locale))
-                    ,_createKeywordEntry("4", translate.text("Lost", locale))
-                ]);
-                break;
             case "TASK.PRIORITY":
                 valueContainer = _createKeywordEntriesContainer([
                      _createKeywordEntry("0", translate.text("{$TASK_PRIORITY_NONE}", locale), null, {defaultAvatarRepresentation: null})
diff --git a/process/Offer_lib/process.js b/process/Offer_lib/process.js
index ad45ec9e4efd4b91501596af489df44bb84e8e68..f39bf78ac6421e0d3b62894c5cc77441db549945 100644
--- a/process/Offer_lib/process.js
+++ b/process/Offer_lib/process.js
@@ -56,7 +56,7 @@ OfferUtils.getOfferNumberValidationFailString = function() {
 }
     
 OfferUtils.isEditable = function(status) {
-    // TODO: Administrator darf immer ändern, warten auf neue Berechtigungslogik?
+    // TODO: Administrator darf immer ändern, warten auf neue Berechtigungslogik?
 
     // Offer should be editable if offer state not equals "Sent", "Won" or "Lost"
     return status != "2" && status != "3" && status != "4";
@@ -108,7 +108,7 @@ OfferUtils.openOfferReport = function(pOfferID)
     var offerCondition = SqlCondition.begin().andPrepare("OFFER.OFFERID", pOfferID);
     var rptdata = db.table(offerCondition.buildSql("select " + fields.join(", ") + offerFromSql, "1 = 0"));
     
-    var language = "deu" //KeywordUtils.get("LANGUAGE", rptdata[0][2])[1];
+    var language = LegacyKeywordUtils.get("LANGUAGE", rptdata[0][2])[1];
     var relid = rptdata[0][1];
     
     // TODO: AddrObject implementieren
@@ -148,7 +148,7 @@ OfferUtils.openOfferReport = function(pOfferID)
         }
         // itemSum * "OFFERITEM_VAT" / 100
         vatsum = (eMath.divDec(eMath.mulDec(itemSum, rptdata[i][26] ), 100)); //Steuerbetrag in Euro je Artikel
-        if(rptdata[i][26] > 0) sums.push([rptdata[i][26], vatsum]); //MWSteuerwerte für Map vorbereiten
+        if(rptdata[i][26] > 0) sums.push([rptdata[i][26], vatsum]); //MWSteuerwerte für Map vorbereiten
         // sumItemSum + "OFFER_VAT"
         total = eMath.addDec(sumItemSum, rptdata[i][20]); //Gesamtsumme zzgl. MwSt.
         total = text.formatDouble(total, translate.text("#,##0.00"), true)
@@ -160,11 +160,11 @@ OfferUtils.openOfferReport = function(pOfferID)
         rptdata[i][21] = text.formatDouble(rptdata[i][21], translate.text("#,##0"), true);
         rptdata[i][26] = text.formatDouble(rptdata[i][26], translate.text("#,##0.00"), true);
         rptdata[i][27] = text.formatDouble(itemSum, translate.text("#,##0.00"), true); //Immer zwei Nachkommastellen und ',' statt '.' 
-        rptdata[i][28] = "dummy2"// KeywordUtils.get($KeywordRegistry.get.QuantityUnit, rptdata[i][19])[1];
+        rptdata[i][28] = KeywordUtils.get("UNIT", rptdata[i][19])[1];
     }
     
     // TODO: get Images implementieren
-    var imgData = ["meineFirma | Konrad-Zuse-Straße 4  |  DE 84144 Geisenhausen",
+    var imgData = ["meineFirma | Konrad-Zuse-Straße 4  |  DE 84144 Geisenhausen",
                    "base64:iVBORw0KGgoAAAANSUhEUgAAAM4AAABRCAYAAACaL5lSAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYxIDY0LjE0MDk0OSwgMjAxMC8xMi8wNy0xMDo1NzowMSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNS4xIFdpbmRvd3MiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6MDA4QzAyM0IwREIwMTFFNEFGMDREM0VEMjExRjlBRTIiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MDA4QzAyM0MwREIwMTFFNEFGMDREM0VEMjExRjlBRTIiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDowMDhDMDIzOTBEQjAxMUU0QUYwNEQzRUQyMTFGOUFFMiIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDowMDhDMDIzQTBEQjAxMUU0QUYwNEQzRUQyMTFGOUFFMiIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PhF3nYoAAAlvSURBVHja7J1fjBXVHcfPJQJRoe1urQYJRBYlMUJisqwvGNjY3WgEUtN2CeWBIGb3Ju6LElsW+gA8AHe1UfuwTcBASB/Q7CZNG0tjw2pWU15kNzEBJFnLqmvQBNEbU0pbX+jve+9vlrOzM/fOnTtz78zs95P8cv/MOTPnzJzvnN/5zZ+Tu3XrliGE1MYC7gJCKBxCKBxCKBxCKBxCKBxCCIVDCIVDCIVDCIVDyDzmDq8/d+1/PY5trRB7VGyt2BqxVWLLxe4RW6JpbohdF7sq9qnYpNhFsY/Evoi6QKeOvMAWQKITToQ8LPaEWKfYBrFlVdL/SO1BsU3W/1+JnRMbE3tP7DIPHcmicLrFfia2VWxlBOuD4H6pNi32tthfxM7yEJIsCAc9yw6x7WJLYyozhNgvtlPsLbHT2hMRkjrhYPzynNhu/d4IIMxesafEToqdiGMcREhcwnlKe4AtTaoDhHpArF1sSOwdHlYSN/WGo/Niv2+iaGy2aFnyPKwkqT1OTmyf2pIE1Qdh7t+J/VjsqBgfbyWJEU5OXaMDCa0ThHxYbJHYIYqHJMVV25dg0dgc0LIS0nTh5FPWGPdxzEOaLRxEz/YkbEwTxG3bo2UnpOHCQci3XwffaWONln0FDzdptHBwcXNLiuu5RetASMOE02nKdwSknd1aF0IaIpwdGXFzVmhdCIldOLjLeXuG6rtd60RIrMLBowFLM1TfpVonQmITDh5C25rBOm/VuhESi3Dw5ObKDNZ5pdaNkFiE05nhenfy0JM4hIMI1IYM13uD4QVREoNw8DaaZRmu9zKtIyGh8HusYG3UG/pJ6w/NKy89O/P70j+nzSsn/zTz+5EHV5oHlt9rep58fFa+sQ8vmEtXps35C5/4+12PrTMP3H9v6dMGeZAX6/Cp49tsAiRK4TTsnrS771xsdj3TZTrWPeQrCtiljmnzhzfPmH//538zyyC0/l9tLonSC6wT1tmxzgxJ3q+//a4pdSTzx1Vb1SjR/Hr3L3xFY4MeCWnt3wf7d/iKxgYC+83un7vTruLhJ1H3OMsbsfHnpbdAo0Yv8rcPzpsz74/P6i3QU0AgtgA2b1pvPhQXDHltd+7MB+MzPQrSIa/tukE0mzeuN6f+/O6cOuZyubrr0tvb12bK73nDZ/cbbxwfzWKD2Tnw2l75KIiN/rHwYibvwggyobSfcO6Ju3COINDYX5axjsuNKo1PYLue+eksATy9scN0rF1T6q0AxkkYL9l8dvWaOXX1XfPZl9dK+W23zxJY1HXsUtEANK7RBDf+s1reakyJOFa7/utz6ivr6ZLlmTxBhHXVGvawmsfYYxYjf//HrHENBIMexVnmFs2cwIJr+WO33cKo64gGNKXfBzPcZo479Z2voqnU4zQENGz0DpWAaJAOLpoNxGa7dn6cv/jJbHfv/vtiqYu4ZhDN6pQd/5rdLUk/mPETQ109zo2GCOf8hUDpPr4yHTqvu8exAgQ3DCERC+d63BtGT1Ktt3G45uHK+VybmYPbDbSEc52Hn0QtnKtxb7jSuKZaWojOHvfUkt8JKjSijmT+jXEwqdOmeHuc/4bOe7OOvK46etLb24eoWI8pv4/aHhSP+IWZNRx9RX/mJd3xasvlP2wDUSo7wlUaQ8jyYrUKhClnvewceO2Yltkr4maHq0vLEXkz5SijU8duJ6jgXpf8btPfe937Q5YXNU+LpilYaSY0zUiVsrdrObD+FmsR8o1Uyx+kx5mcByeNSa/GLzauB6XdtRgH66w21rqR9aDRDJu5YWGsf1yF5pe3YeWsU2QoW6DQt6a94hLNzP6AYFRY4y7RGN0Hwypav/UXrLwtrsU91fIHFc7FeSCci67G2KIHGQehqL1CDmbK0TLnbFSQtH11brtPbdDaRqu5Hept82hAzShnveDEgN5ltZzNc2pePaFTJ5S9Fel89sewfs876zPlR+GdywAFFZcX7VYPtj5E/kCuGubcxPSBWb1D+iuto01BDwp2YreGl0vo923SEIf17LTXOqhhaHe7c+qa5VUYJRdOvg94uGxRlhMXMStdJu+u41oNyjgRMNzdoq7SNucPdc3y2pC7rBPJNtulQvkkTd7cnp2vx3iHyydUcFP2nzXkD9TjYIKmcxnubc4ZaxIqbazO2XnQbowunB0KV6m9ju2PusdALn/bfZZsVjnrZTCCtPZ+8hyHqLinLMEajzQDbtG48hcr5Q/a44AxU55zM4uMefi4Xg13FtJQJ6Qh2o16IqxwAi5ri7mcsd5vVsNguyhp/co44fPdzZTur7aQxZ0wwW5DqioczO6Mq4dZfO/Aex5uhcO3VqOr5l6EpVih0RcrbL/R5ayHqSj2RwURhdqeFZWzx5s1i62ScDAlOh706s+gcC4npHHVSoshoRDB9Fjjw7qpdq8apkTH7M5LM75fnTNeUc74rSxn5kTjXFtyGLDHUAhE1HDHeCDhYGWYEr13nginBQPwIBcfWc5UsdcKLmyLYoVB3h192mR/GvRRnwE4y5n+3qbdcnErBSvaoxbOmNjJLO9cRKGsgWehylX7rmZdlU9LOdM2RtS7ClqiFg44IfbXtO6thQvvuBkgWd7auePuRqcN8Zi5faGsWaSlnIlAw9yOS1vQIIEjmDb7frkogwMOcNWGTPnNMGl7O8zknYsX/UA+76p2NpcGB/93WBslzugFn+QTzapMWsqZMPLW/sI9ae7l3ToOChxxq2UO0HfEXjXpegAMZX118aKFNwM2SvjAqzXqUvRohPi/tdkv4khLORPU64yoONxjHNyVsD7MbUU5rzd67Nr/eqU8+8UOp2Sf/VbsiN/CU0deYKsioVgQIs9RsUMpqNshLSshkRPmZR23tFF+L7bPJG/69hsqmKNaVkISIRxHPHCBvhHbk6CAwaSOw47x0JIkCscBDfRzU76frdnTuSNcPqRBDEISLRyjDfWSKUdzMCV6o+edQagcF2hPmOzf4UAyJByn8R405bsMMCU6ZneO+8bQf5nyfXSnzdznawhJhXAcxtQQL8fszpioNurnefCMEB53wJ3bvDpOMiEch7NqGHNgotpOU54+MOw7DPCOgHMqSjyEdpmHjmRROA6X1YZ07IPpAzETGqJwmJ8GU21g1gAnpI1QMt6wiZcF4r1niJLhbTQfcfxCkkQuyFwghJDZLOAuIITCIYTCIYTCIYTCIYTCIYRQOIRQOIRQOIRQOIRQOISQWvi/AAMA9UczDEaG0p8AAAAASUVORK5CYII="]
                 // getMyASYS_ICONSdata();
     
@@ -194,7 +194,7 @@ OfferUtils.openOfferReport = function(pOfferID)
     params["OFFERPay"] = ""//getKeyName(rptdata[0][3] , "PAYMENTTERMS", "KEYNAME1", language);
     params["OFFERDel"] = ""//getKeyName(rptdata[0][4] , "DELIVERYTERMS", "KEYNAME1", language);
     
-    // TODO: implementieren wenn Attribute möglich sind
+    // TODO: implementieren wenn Attribute möglich sind
     var adma = ""
     /*var adm = getAddressData( [GetAttributeKey( "Aussendienst", "1", orgrelid, pUser )[0]],
         [["Person","function", "concat( ['SALUTATION', 'TITLE', 'FIRSTNAME','LASTNAME'])"],
@@ -231,32 +231,6 @@ OfferUtils.openOfferReport = function(pOfferID)
     offerReport.openReport();
 }
 
-/**
- * opens an order in NEW mode with values from an offer
- * 
- * @param pOfferId {String} id of the offer
- * @param pSalesprojectId {String} salesproject id
- * @param pContactId {String} contact id
- * @param pLanguage {String} language
- * @param pCurrency {String} [currency=""]
- * @param pAddress {String} [address=""]
- * @param pHeader {String} [header=""]
- */
-OfferUtils.copyToOrder = function (pOfferId, pSalesprojectId, pContactId, pLanguage, pCurrency, pAddress, pHeader)
-{
-    var params = {
-        "ContactId_param" : pContactId,
-        "SalesprojectId_param" : pSalesprojectId,
-        "OrderLanguage_param" : pLanguage,
-        "OfferId_param" : pOfferId,
-        "OrderCurrency_param" : pCurrency || "",
-        "OrderAddress_param" : pAddress || "",
-        "OrderHeader_param" : pHeader || ""
-    };
-    neon.openContext("Order_context", null, null, neon.OPERATINGSTATE_NEW, params);
-}
-
-
 /******************************************************************************/
 
 /**
@@ -336,3 +310,4 @@ OfferItemUtils.prototype.reOrgItems = function() {
     
     ItemUtils.prototype.reOrgItems.apply(this);
 }
+
diff --git a/process/Organisation_lib/process.js b/process/Organisation_lib/process.js
index 9816a157cb98eb7f7baadd145e729edc37f7466e..793d7d0ecd7b102a8129224553d64550e086a057 100644
--- a/process/Organisation_lib/process.js
+++ b/process/Organisation_lib/process.js
@@ -75,7 +75,7 @@ OrgUtils.openOrgReport = function(pOrgId)
     //resolve keyword
     commData.forEach(function (row)
     {
-        row[0] = KeywordUtils.getViewValue("COMMUNICATION.MEDIUM", row[0]);
+        row[0] = LegacyKeywordUtils.getViewValue("COMMUNICATION.MEDIUM", row[0]);
     });
     commData = ReportData.begin(["KINDOFCOMM", "COMMVALUE"]).add(commData);
     
@@ -91,7 +91,7 @@ OrgUtils.openOrgReport = function(pOrgId)
     
     //TODO: get the keywords in another way when keywords are entitys
     var mediumIds = [];
-    var mediums = KeywordUtils.getStandardArrayProps("COMMUNICATION.MEDIUM");
+    var mediums = LegacyKeywordUtils.getStandardArrayProps("COMMUNICATION.MEDIUM");
     for (let i = 0; i < mediums.length; i++)
         if ("category" in mediums[i][2] && (mediums[i][2].category == "PHONE" || mediums[i][2].category == "EMAIL"))
             mediumIds.push(mediums[i][0]);
@@ -113,7 +113,7 @@ OrgUtils.openOrgReport = function(pOrgId)
         //resolve keyword
         persData[i][3] = persDataComm.map(function (row)
             {
-                return KeywordUtils.getViewValue("COMMUNICATION.MEDIUM", row[0]) + ": " + row[1];
+                return LegacyKeywordUtils.getViewValue("COMMUNICATION.MEDIUM", row[0]) + ": " + row[1];
             }
         ).join("\n");
     }
@@ -132,7 +132,7 @@ OrgUtils.openOrgReport = function(pOrgId)
     histData.forEach(function (row) 
     {
         row[0] = datetime.toDate(row[0], dateFormat);
-        row[1] = KeywordUtils.getViewValue("ACTIVITY.CATEGORY", row[1]);
+        row[1] = LegacyKeywordUtils.getViewValue("ACTIVITY.CATEGORY", row[1]);
         _joinArrayVals(row, 2, 2);
     });
     histData = ReportData.begin(["ENTRYDATE", "MEDIUM", "LOGIN", "INFO"]).add(histData);
diff --git a/process/PostalAddress_lib/process.js b/process/PostalAddress_lib/process.js
index 2cf3d815717294418fe8642b9e1895ed5025e054..8d31f07afec4252a16224dd689792654c647187c 100644
--- a/process/PostalAddress_lib/process.js
+++ b/process/PostalAddress_lib/process.js
@@ -137,7 +137,7 @@ AddressUtils.getAllPossibleAddresses = function(pRelationId) {
                                                      .buildSql("select ADDRESSID, ADDR_TYPE, ADDRIDENTIFIER from ADDRESS join CONTACT on CONTACTID = CONTACT_ID or CONTACT_ID = ORGANISATION_ID", "1=0"));
                                                      
     return addresses.map(function(pAddress) {
-        return [pAddress[0], KeywordUtils.get("ADDRESS.TYPE", pAddress[1])[1] + " " + pAddress[2]]
+        return [pAddress[0], LegacyKeywordUtils.get("ADDRESS.TYPE", pAddress[1])[1] + " " + pAddress[2]]
     });
 }
 
diff --git a/process/Product_lib/process.js b/process/Product_lib/process.js
index dac426957e4c40b1c8ca842b7362f3fdb98c280d..72b442f09b175bf1f2b33eb7b7cf47c19faa9f3d 100644
--- a/process/Product_lib/process.js
+++ b/process/Product_lib/process.js
@@ -44,7 +44,7 @@ ProductUtils.getCurrentProductPrice = function(pid, buySell) {
         var productPriceData = db.array(db.ROW, actualPriceCondition.buildSql("select PRICE, CURRENCY from PRODUCTPRICE", "1 = 2", "order by VALID_FROM desc"));
         
         if (productPriceData[0] && productPriceData[1])
-            return  productPriceData[0] + " " + KeywordUtils.get("CURRENCY", productPriceData[1])[1];
+            return  productPriceData[0] + " " + LegacyKeywordUtils.get("CURRENCY", productPriceData[1])[1];
         else
             return "";
     } else {
diff --git a/process/Salesproject_lib/process.js b/process/Salesproject_lib/process.js
index acbb272a3e6cb68372a05e176884ef760b9402ce..3ca5cd3d006d00d888830cf349654874a82ee57d 100644
--- a/process/Salesproject_lib/process.js
+++ b/process/Salesproject_lib/process.js
@@ -48,7 +48,7 @@ Salesproject.validateProjectNumber = function(projectNumber) {
  * @result {Boolean} true if inserted, else false
  */
 Salesproject.insertMilestone = function(salesprojectId, type, value, notifyForecast) {
-    if (KeywordUtils.createKeyword("SALESPROJECT.CYCLE.TYPE").exists(type)) {
+    if (LegacyKeywordUtils.createKeyword("SALESPROJECT.CYCLE.TYPE").exists(type)) {
         db.insertData(
             "SALESPROJECT_CYCLE",
             ["SALESPROJECT_CYCLEID", "SALESPROJECT_ID", "TYPE", "VALUE", "DATE_START"],
diff --git a/process/Sql_lib/process.js b/process/Sql_lib/process.js
index 2e8ad26e765ecbd062a20815ea406085d497c024..50d0d7ba393dd1d70667592d9881d317c96a1000 100644
--- a/process/Sql_lib/process.js
+++ b/process/Sql_lib/process.js
@@ -83,25 +83,6 @@ SqlCondition.prototype.and = function(cond) {
     return this;
 }
 
-/**
- * same as the "and"-function but with preparedStatement functionality
- * @param {String} field the database field as "tablename.columnname"; e.g. "ORGANISATION.NAME"
- * @param {String} value the value that shall be set into the prepared statement
- * @param {String} [cond="# = ?"] the strucutre of the SQL condition as preparedString, you can use a number sign "#" as placeholder for you fieldname; 
- *                 e.g. "# > ?"; escaping the number sign is possible with a backslash "\"
- * @param {Numeric | Boolean} [fieldType] SQL-column-type; if the fieldType is not given it's loaded automatically;
- *                              The loaded type is cached if no type is given. So it is also safe to use this in a loop.
- *                              e.g.
- *                              for (...) {
- *                                  cond.andPrepare("SALESPROJECT_CLASSIFICATION.TYPE", entry, "# <> ?")
- *                              }
- * @return {SqlCondition} current SqlCondition-object
- */
-SqlCondition.prototype.andPrepare = function(field, value, cond, fieldType) {
-    cond = this._prepare(field, value, cond, fieldType);
-    return this.and(cond);
-}
-
 /**
  * append with SQL-or; Also paranthesize the existing conditions
  * @param {String} cond the condition string which shall be appended
@@ -126,17 +107,37 @@ SqlCondition.prototype.or = function(cond) {
 }
 
 /**
- * append another condition with SQL-or; Also paranthesize the existing conditions
+ * append a prepared-array to this sql condition with SQL-and
+ * @param {Array} preparedObj a prepared condition-array
+ * @return {SqlCondition} current SqlCondition-object
+ */
+SqlCondition.prototype.andAttachPrepared = function(preparedObj) {
+    this.preparedValues = this.preparedValues.concat(preparedObj[1]);
+    return this.and(preparedObj[0]);
+}
+
+/**
+ * append a prepared-array to this sql condition with SQL-or
+ * @param {Array} preparedObj a prepared condition-array
+ * @return {SqlCondition} current SqlCondition-object
+ */
+SqlCondition.prototype.orAttachPrepared = function(preparedObj) {
+    this.preparedValues.push(preparedObj[1]);
+    return this.or(preparedObj[0]);
+}
+
+/**
+ * append another condition with SQL-and
  * 
  * @param {SqlCondition} cond the condition which shall be appended
  * @param {String} [alternativeCond=""] condition if the given SqlCondition has none
  * @return {SqlCondition} current SqlCondition-object
  */
-SqlCondition.prototype.orSqlCondition = function(cond, alternativeCond) {
+SqlCondition.prototype.andSqlCondition = function(cond, alternativeCond) {
     var otherCondition = cond.toString(alternativeCond);
     if (otherCondition.trim() != "")
     {
-        this.or(" ( " + cond.toString(alternativeCond) + " ) ");
+        this.and(" ( " + cond.toString(alternativeCond) + " ) ");
         if (cond.preparedValues) {
             this.preparedValues = this.preparedValues.concat(cond.preparedValues);
         }
@@ -145,17 +146,17 @@ SqlCondition.prototype.orSqlCondition = function(cond, alternativeCond) {
 }
 
 /**
- * append another condition with SQL-and
+ * append another condition with SQL-or; Also paranthesize the existing conditions
  * 
  * @param {SqlCondition} cond the condition which shall be appended
  * @param {String} [alternativeCond=""] condition if the given SqlCondition has none
  * @return {SqlCondition} current SqlCondition-object
  */
-SqlCondition.prototype.andSqlCondition = function(cond, alternativeCond) {
+SqlCondition.prototype.orSqlCondition = function(cond, alternativeCond) {
     var otherCondition = cond.toString(alternativeCond);
     if (otherCondition.trim() != "")
     {
-        this.and(" ( " + cond.toString(alternativeCond) + " ) ");
+        this.or(" ( " + cond.toString(alternativeCond) + " ) ");
         if (cond.preparedValues) {
             this.preparedValues = this.preparedValues.concat(cond.preparedValues);
         }
@@ -163,6 +164,25 @@ SqlCondition.prototype.andSqlCondition = function(cond, alternativeCond) {
     return this;
 }
 
+/**
+ * same as the "and"-function but with preparedStatement functionality
+ * @param {String} field the database field as "tablename.columnname"; e.g. "ORGANISATION.NAME"
+ * @param {String} value the value that shall be set into the prepared statement
+ * @param {String} [cond="# = ?"] the strucutre of the SQL condition as preparedString, you can use a number sign "#" as placeholder for you fieldname; 
+ *                 e.g. "# > ?"; escaping the number sign is possible with a backslash "\"
+ * @param {Numeric | Boolean} [fieldType] SQL-column-type; if the fieldType is not given it's loaded automatically;
+ *                              The loaded type is cached if no type is given. So it is also safe to use this in a loop.
+ *                              e.g.
+ *                              for (...) {
+ *                                  cond.andPrepare("SALESPROJECT_CLASSIFICATION.TYPE", entry, "# <> ?")
+ *                              }
+ * @return {SqlCondition} current SqlCondition-object
+ */
+SqlCondition.prototype.andPrepare = function(field, value, cond, fieldType) {
+    cond = this._prepare(field, value, cond, fieldType);
+    return this.and(cond);
+}
+
 /**
  * same as the "or"-function but with preparedStatement functionality
  * @param {String} field the database field as "tablename.columnname"; e.g. "ORGANISATION.NAME"