[418619] Add custom EAnnotation validation support

diff --git a/features/org.eclipse.emf.ecore.edit-feature/feature.xml b/features/org.eclipse.emf.ecore.edit-feature/feature.xml
index 004d022..1dd58f9 100644
--- a/features/org.eclipse.emf.ecore.edit-feature/feature.xml
+++ b/features/org.eclipse.emf.ecore.edit-feature/feature.xml
@@ -2,7 +2,7 @@
 <feature
       id="org.eclipse.emf.ecore.edit"
       label="%featureName"
-      version="2.9.0.qualifier"
+      version="2.10.0.qualifier"
       provider-name="%providerName"
       license-feature="org.eclipse.emf.license"
       license-feature-version="2.8.0.qualifier">
diff --git a/plugins/org.eclipse.emf.codegen.ecore.ui/plugin.properties b/plugins/org.eclipse.emf.codegen.ecore.ui/plugin.properties
index e0eb501..f9b6c04 100644
--- a/plugins/org.eclipse.emf.codegen.ecore.ui/plugin.properties
+++ b/plugins/org.eclipse.emf.codegen.ecore.ui/plugin.properties
@@ -467,3 +467,28 @@
 _UI_GenEclipsePlatformVersion_Neon_literal = Neon - 4.6
 _UI_GenEclipsePlatformVersion_Oxygen_literal = Oxygen - 4.7
 _UI_GenEclipsePlatformVersion_Photon_literal = Photon - 4.8
+
+
+_UI_GenModel_modelDocumentation_feature = Model Documentation
+_UI_GenModel_modelDocumentation_description = The Javadoc documentation to generate for the model-level artifacts such as plug-in classes, including any @since or @deprecated tags
+_UI_GenPackage_documentation_feature = Documentation
+_UI_GenPackage_documentation_description = The Javadoc to be generated, including any @since or @deprecated tags
+_UI_GenFeature_suppressedGetVisibility_feature = Suppressed Get Visibility
+_UI_GenFeature_suppressedGetVisibility_description = Whether to suppress the generated get accessor from the interface
+_UI_GenFeature_suppressedSetVisibility_feature = Suppressed Set Visibility
+_UI_GenFeature_suppressedSetVisibility_description = Whether to suppress the generated set accessor from the interface
+_UI_GenFeature_suppressedIsSetVisibility_feature = Suppressed Is Set Visibility
+_UI_GenFeature_suppressedIsSetVisibility_description = Whether to suppress the generated is-set accessor from the interface
+_UI_GenFeature_suppressedUnsetVisibility_feature = Suppressed Unset Visibility
+_UI_GenFeature_suppressedUnsetVisibility_description = Whether to suppress the generated unset accessor from the interface
+_UI_GenEnumLiteral_documentation_feature = Documentation
+_UI_GenEnumLiteral_documentation_description = The Javadoc to be generated, including any @since or @deprecated tags
+_UI_GenClassifier_documentation_feature = Documentation
+_UI_GenClassifier_documentation_description = The Javadoc to be generated, including any @since or @deprecated tags
+_UI_GenOperation_suppressedVisibility_feature = Suppressed Visibility
+_UI_GenOperation_suppressedVisibility_description = Whether to suppress the generated method from the interface
+_UI_GenTypedElement_documentation_feature = Documentation
+_UI_GenTypedElement_documentation_description = The Javadoc to be generated, including any @since or @deprecated tags
+_UI_GenTypeParameter_documentation_feature = Documentation
+_UI_GenTypeParameter_documentation_description = The Javadoc to be generated
+_UI_GenParameter_documentation_description = The Javadoc to be generated
diff --git a/plugins/org.eclipse.emf.codegen.ecore.ui/plugin.xml b/plugins/org.eclipse.emf.codegen.ecore.ui/plugin.xml
index aefe392..ab3981d 100644
--- a/plugins/org.eclipse.emf.codegen.ecore.ui/plugin.xml
+++ b/plugins/org.eclipse.emf.codegen.ecore.ui/plugin.xml
@@ -39,7 +39,15 @@
                org.eclipse.emf.edit.provider.IItemLabelProvider
                org.eclipse.emf.edit.provider.IItemPropertySource"/>
    </extension>
-   
+
+   <extension
+         point="org.eclipse.emf.ecore.edit.annotation_item_provider_adapter_factory">
+      <factory
+            uri="http://www.eclipse.org/emf/2002/GenModel"
+            class="org.eclipse.emf.codegen.ecore.genmodel.provider.GenModelEAnnotationItemProviderAdapterFactory">
+      </factory>
+   </extension>
+
    <extension point="org.eclipse.ui.commands">
       <category
             id="org.eclipse.emf.codegen.ecore.ui.Commands"
diff --git a/plugins/org.eclipse.emf.codegen.ecore.ui/src/org/eclipse/emf/codegen/ecore/genmodel/provider/GenClassItemProvider.java b/plugins/org.eclipse.emf.codegen.ecore.ui/src/org/eclipse/emf/codegen/ecore/genmodel/provider/GenClassItemProvider.java
index 5dd5543..169d548 100644
--- a/plugins/org.eclipse.emf.codegen.ecore.ui/src/org/eclipse/emf/codegen/ecore/genmodel/provider/GenClassItemProvider.java
+++ b/plugins/org.eclipse.emf.codegen.ecore.ui/src/org/eclipse/emf/codegen/ecore/genmodel/provider/GenClassItemProvider.java
@@ -64,6 +64,7 @@
     {
       super.getPropertyDescriptors(object);
 
+      addDocumentationPropertyDescriptor(object);
       addProviderPropertyDescriptor(object);
       addImagePropertyDescriptor(object);
       addDynamicPropertyDescriptor(object);
@@ -74,6 +75,30 @@
   }
 
   /**
+   * This adds a property descriptor for the Documentation feature.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @since 2.14
+   * @generated
+   */
+  protected void addDocumentationPropertyDescriptor(Object object)
+  {
+    itemPropertyDescriptors.add
+      (createItemPropertyDescriptor
+        (((ComposeableAdapterFactory)adapterFactory).getRootAdapterFactory(),
+         getResourceLocator(),
+         getString("_UI_GenClassifier_documentation_feature"),
+         getString("_UI_GenClassifier_documentation_description"),
+         GenModelPackage.Literals.GEN_CLASSIFIER__DOCUMENTATION,
+         true,
+         true,
+         false,
+         ItemPropertyDescriptor.GENERIC_VALUE_IMAGE,
+         getString("_UI_ModelPropertyCategory"),
+         null));
+  }
+
+  /**
    * This adds a property descriptor for the Provider feature.
    * <!-- begin-user-doc -->
    * <!-- end-user-doc -->
@@ -288,6 +313,7 @@
     {
       case GenModelPackage.GEN_CLASS__GEN_PACKAGE:
       case GenModelPackage.GEN_CLASS__GEN_TYPE_PARAMETERS:
+      case GenModelPackage.GEN_CLASS__DOCUMENTATION:
       case GenModelPackage.GEN_CLASS__PROVIDER:
       case GenModelPackage.GEN_CLASS__IMAGE:
       case GenModelPackage.GEN_CLASS__DYNAMIC:
diff --git a/plugins/org.eclipse.emf.codegen.ecore.ui/src/org/eclipse/emf/codegen/ecore/genmodel/provider/GenDataTypeItemProvider.java b/plugins/org.eclipse.emf.codegen.ecore.ui/src/org/eclipse/emf/codegen/ecore/genmodel/provider/GenDataTypeItemProvider.java
index 2196bbe..0aa360a 100644
--- a/plugins/org.eclipse.emf.codegen.ecore.ui/src/org/eclipse/emf/codegen/ecore/genmodel/provider/GenDataTypeItemProvider.java
+++ b/plugins/org.eclipse.emf.codegen.ecore.ui/src/org/eclipse/emf/codegen/ecore/genmodel/provider/GenDataTypeItemProvider.java
@@ -21,10 +21,9 @@
 import org.eclipse.emf.ecore.EDataType;
 import org.eclipse.emf.edit.provider.ComposeableAdapterFactory;
 import org.eclipse.emf.edit.provider.IItemPropertyDescriptor;
+import org.eclipse.emf.edit.provider.ItemPropertyDescriptor;
 import org.eclipse.emf.edit.provider.ViewerNotification;
 
-// import org.eclipse.emf.edit.provider.ItemPropertyDescriptor;
-
 
 /**
  * This is the item provider adapter for a {@link org.eclipse.emf.codegen.ecore.genmodel.GenDataType} object.
@@ -59,12 +58,37 @@
     {
       super.getPropertyDescriptors(object);
 
+      addDocumentationPropertyDescriptor(object);
       addEcoreDataTypePropertyDescriptor(object);
     }
     return itemPropertyDescriptors;
   }
 
   /**
+   * This adds a property descriptor for the Documentation feature.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @since 2.14
+   * @generated
+   */
+  protected void addDocumentationPropertyDescriptor(Object object)
+  {
+    itemPropertyDescriptors.add
+      (createItemPropertyDescriptor
+        (((ComposeableAdapterFactory)adapterFactory).getRootAdapterFactory(),
+         getResourceLocator(),
+         getString("_UI_GenClassifier_documentation_feature"),
+         getString("_UI_GenClassifier_documentation_description"),
+         GenModelPackage.Literals.GEN_CLASSIFIER__DOCUMENTATION,
+         true,
+         true,
+         false,
+         ItemPropertyDescriptor.GENERIC_VALUE_IMAGE,
+         getString("_UI_ModelPropertyCategory"),
+         null));
+  }
+
+  /**
    * This adds a property descriptor for the Ecore Data Type feature.
    * <!-- begin-user-doc -->
    * <!-- end-user-doc -->
@@ -126,6 +150,7 @@
     {
       case GenModelPackage.GEN_DATA_TYPE__GEN_PACKAGE:
       case GenModelPackage.GEN_DATA_TYPE__GEN_TYPE_PARAMETERS:
+      case GenModelPackage.GEN_DATA_TYPE__DOCUMENTATION:
       case GenModelPackage.GEN_DATA_TYPE__ECORE_DATA_TYPE:
         fireNotifyChanged(new ViewerNotification(notification, notification.getNotifier(), false, true));
         return;
diff --git a/plugins/org.eclipse.emf.codegen.ecore.ui/src/org/eclipse/emf/codegen/ecore/genmodel/provider/GenEnumLiteralItemProvider.java b/plugins/org.eclipse.emf.codegen.ecore.ui/src/org/eclipse/emf/codegen/ecore/genmodel/provider/GenEnumLiteralItemProvider.java
index eede498..74ce11f 100644
--- a/plugins/org.eclipse.emf.codegen.ecore.ui/src/org/eclipse/emf/codegen/ecore/genmodel/provider/GenEnumLiteralItemProvider.java
+++ b/plugins/org.eclipse.emf.codegen.ecore.ui/src/org/eclipse/emf/codegen/ecore/genmodel/provider/GenEnumLiteralItemProvider.java
@@ -20,10 +20,9 @@
 import org.eclipse.emf.ecore.EEnumLiteral;
 import org.eclipse.emf.edit.provider.ComposeableAdapterFactory;
 import org.eclipse.emf.edit.provider.IItemPropertyDescriptor;
+import org.eclipse.emf.edit.provider.ItemPropertyDescriptor;
 import org.eclipse.emf.edit.provider.ViewerNotification;
 
-// import org.eclipse.emf.edit.provider.ItemPropertyDescriptor;
-
 
 /**
  * This is the item provider adapter for a {@link org.eclipse.emf.codegen.ecore.genmodel.GenEnumLiteral} object.
@@ -59,6 +58,7 @@
       super.getPropertyDescriptors(object);
 
       addEcoreEnumLiteralPropertyDescriptor(object);
+      addDocumentationPropertyDescriptor(object);
     }
     return itemPropertyDescriptors;
   }
@@ -87,6 +87,30 @@
   }
 
   /**
+   * This adds a property descriptor for the Documentation feature.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @since 2.14
+   * @generated
+   */
+  protected void addDocumentationPropertyDescriptor(Object object)
+  {
+    itemPropertyDescriptors.add
+      (createItemPropertyDescriptor
+        (((ComposeableAdapterFactory)adapterFactory).getRootAdapterFactory(),
+         getResourceLocator(),
+         getString("_UI_GenEnumLiteral_documentation_feature"),
+         getString("_UI_GenEnumLiteral_documentation_description"),
+         GenModelPackage.Literals.GEN_ENUM_LITERAL__DOCUMENTATION,
+         true,
+         true,
+         false,
+         ItemPropertyDescriptor.GENERIC_VALUE_IMAGE,
+         getString("_UI_ModelPropertyCategory"),
+         null));
+  }
+
+  /**
    */
   @Override
   public Object getImage(Object object)
@@ -120,6 +144,7 @@
     switch (notification.getFeatureID(GenEnumLiteral.class))
     {
       case GenModelPackage.GEN_ENUM_LITERAL__ECORE_ENUM_LITERAL:
+      case GenModelPackage.GEN_ENUM_LITERAL__DOCUMENTATION:
         fireNotifyChanged(new ViewerNotification(notification, notification.getNotifier(), false, true));
         return;
     }
diff --git a/plugins/org.eclipse.emf.codegen.ecore.ui/src/org/eclipse/emf/codegen/ecore/genmodel/provider/GenFeatureItemProvider.java b/plugins/org.eclipse.emf.codegen.ecore.ui/src/org/eclipse/emf/codegen/ecore/genmodel/provider/GenFeatureItemProvider.java
index ff06f80..6af3902 100644
--- a/plugins/org.eclipse.emf.codegen.ecore.ui/src/org/eclipse/emf/codegen/ecore/genmodel/provider/GenFeatureItemProvider.java
+++ b/plugins/org.eclipse.emf.codegen.ecore.ui/src/org/eclipse/emf/codegen/ecore/genmodel/provider/GenFeatureItemProvider.java
@@ -62,6 +62,7 @@
     {
       super.getPropertyDescriptors(object);
 
+      addDocumentationPropertyDescriptor(object);
       addPropertyPropertyDescriptor(object);
       addNotifyPropertyDescriptor(object);
       addChildrenPropertyDescriptor(object);
@@ -72,11 +73,39 @@
       addPropertyMultiLinePropertyDescriptor(object);
       addPropertySortChoicesPropertyDescriptor(object);
       addEcoreFeaturePropertyDescriptor(object);
+      addSuppressedGetVisibilityPropertyDescriptor(object);
+      addSuppressedSetVisibilityPropertyDescriptor(object);
+      addSuppressedIsSetVisibilityPropertyDescriptor(object);
+      addSuppressedUnsetVisibilityPropertyDescriptor(object);
     }
     return itemPropertyDescriptors;
   }
 
   /**
+   * This adds a property descriptor for the Documentation feature.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @since 2.14
+   * @generated
+   */
+  protected void addDocumentationPropertyDescriptor(Object object)
+  {
+    itemPropertyDescriptors.add
+      (createItemPropertyDescriptor
+        (((ComposeableAdapterFactory)adapterFactory).getRootAdapterFactory(),
+         getResourceLocator(),
+         getString("_UI_GenTypedElement_documentation_feature"),
+         getString("_UI_GenTypedElement_documentation_description"),
+         GenModelPackage.Literals.GEN_TYPED_ELEMENT__DOCUMENTATION,
+         true,
+         true,
+         false,
+         ItemPropertyDescriptor.GENERIC_VALUE_IMAGE,
+         getString("_UI_ModelPropertyCategory"),
+         null));
+  }
+
+  /**
    * This adds a property descriptor for the Property feature.
    * <!-- begin-user-doc -->
    * <!-- end-user-doc -->
@@ -307,6 +336,102 @@
   }
 
   /**
+   * This adds a property descriptor for the Suppressed Get Visibility feature.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @since 2.14
+   * @generated
+   */
+  protected void addSuppressedGetVisibilityPropertyDescriptor(Object object)
+  {
+    itemPropertyDescriptors.add
+      (createItemPropertyDescriptor
+        (((ComposeableAdapterFactory)adapterFactory).getRootAdapterFactory(),
+         getResourceLocator(),
+         getString("_UI_GenFeature_suppressedGetVisibility_feature"),
+         getString("_UI_GenFeature_suppressedGetVisibility_description"),
+         GenModelPackage.Literals.GEN_FEATURE__SUPPRESSED_GET_VISIBILITY,
+         true,
+         false,
+         false,
+         ItemPropertyDescriptor.BOOLEAN_VALUE_IMAGE,
+         getString("_UI_ModelPropertyCategory"),
+         null));
+  }
+
+  /**
+   * This adds a property descriptor for the Suppressed Set Visibility feature.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @since 2.14
+   * @generated
+   */
+  protected void addSuppressedSetVisibilityPropertyDescriptor(Object object)
+  {
+    itemPropertyDescriptors.add
+      (createItemPropertyDescriptor
+        (((ComposeableAdapterFactory)adapterFactory).getRootAdapterFactory(),
+         getResourceLocator(),
+         getString("_UI_GenFeature_suppressedSetVisibility_feature"),
+         getString("_UI_GenFeature_suppressedSetVisibility_description"),
+         GenModelPackage.Literals.GEN_FEATURE__SUPPRESSED_SET_VISIBILITY,
+         true,
+         false,
+         false,
+         ItemPropertyDescriptor.BOOLEAN_VALUE_IMAGE,
+         getString("_UI_ModelPropertyCategory"),
+         null));
+  }
+
+  /**
+   * This adds a property descriptor for the Suppressed Is Set Visibility feature.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @since 2.14
+   * @generated
+   */
+  protected void addSuppressedIsSetVisibilityPropertyDescriptor(Object object)
+  {
+    itemPropertyDescriptors.add
+      (createItemPropertyDescriptor
+        (((ComposeableAdapterFactory)adapterFactory).getRootAdapterFactory(),
+         getResourceLocator(),
+         getString("_UI_GenFeature_suppressedIsSetVisibility_feature"),
+         getString("_UI_GenFeature_suppressedIsSetVisibility_description"),
+         GenModelPackage.Literals.GEN_FEATURE__SUPPRESSED_IS_SET_VISIBILITY,
+         true,
+         false,
+         false,
+         ItemPropertyDescriptor.BOOLEAN_VALUE_IMAGE,
+         getString("_UI_ModelPropertyCategory"),
+         null));
+  }
+
+  /**
+   * This adds a property descriptor for the Suppressed Unset Visibility feature.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @since 2.14
+   * @generated
+   */
+  protected void addSuppressedUnsetVisibilityPropertyDescriptor(Object object)
+  {
+    itemPropertyDescriptors.add
+      (createItemPropertyDescriptor
+        (((ComposeableAdapterFactory)adapterFactory).getRootAdapterFactory(),
+         getResourceLocator(),
+         getString("_UI_GenFeature_suppressedUnsetVisibility_feature"),
+         getString("_UI_GenFeature_suppressedUnsetVisibility_description"),
+         GenModelPackage.Literals.GEN_FEATURE__SUPPRESSED_UNSET_VISIBILITY,
+         true,
+         false,
+         false,
+         ItemPropertyDescriptor.BOOLEAN_VALUE_IMAGE,
+         getString("_UI_ModelPropertyCategory"),
+         null));
+  }
+
+  /**
    */
   @Override
   public Object getImage(Object object)
@@ -419,6 +544,7 @@
 
     switch (notification.getFeatureID(GenFeature.class))
     {
+      case GenModelPackage.GEN_FEATURE__DOCUMENTATION:
       case GenModelPackage.GEN_FEATURE__PROPERTY:
       case GenModelPackage.GEN_FEATURE__NOTIFY:
       case GenModelPackage.GEN_FEATURE__CHILDREN:
@@ -429,6 +555,10 @@
       case GenModelPackage.GEN_FEATURE__PROPERTY_MULTI_LINE:
       case GenModelPackage.GEN_FEATURE__PROPERTY_SORT_CHOICES:
       case GenModelPackage.GEN_FEATURE__ECORE_FEATURE:
+      case GenModelPackage.GEN_FEATURE__SUPPRESSED_GET_VISIBILITY:
+      case GenModelPackage.GEN_FEATURE__SUPPRESSED_SET_VISIBILITY:
+      case GenModelPackage.GEN_FEATURE__SUPPRESSED_IS_SET_VISIBILITY:
+      case GenModelPackage.GEN_FEATURE__SUPPRESSED_UNSET_VISIBILITY:
         fireNotifyChanged(new ViewerNotification(notification, notification.getNotifier(), false, true));
         return;
     }
diff --git a/plugins/org.eclipse.emf.codegen.ecore.ui/src/org/eclipse/emf/codegen/ecore/genmodel/provider/GenModelEAnnotationItemProviderAdapterFactory.java b/plugins/org.eclipse.emf.codegen.ecore.ui/src/org/eclipse/emf/codegen/ecore/genmodel/provider/GenModelEAnnotationItemProviderAdapterFactory.java
new file mode 100644
index 0000000..30c3a95
--- /dev/null
+++ b/plugins/org.eclipse.emf.codegen.ecore.ui/src/org/eclipse/emf/codegen/ecore/genmodel/provider/GenModelEAnnotationItemProviderAdapterFactory.java
@@ -0,0 +1,108 @@
+/**
+ * Copyright (c) Eclipse contributors and others.
+ * All rights reserved.   This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.eclipse.emf.codegen.ecore.genmodel.provider;
+
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.eclipse.emf.codegen.ecore.genmodel.GenClass;
+import org.eclipse.emf.codegen.ecore.genmodel.GenFeature;
+import org.eclipse.emf.codegen.ecore.genmodel.GenModelFactory;
+import org.eclipse.emf.codegen.ecore.genmodel.GenModelPackage;
+import org.eclipse.emf.common.util.ResourceLocator;
+import org.eclipse.emf.ecore.EAnnotation;
+import org.eclipse.emf.ecore.EAnnotationValidator;
+import org.eclipse.emf.ecore.EAttribute;
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EStructuralFeature;
+import org.eclipse.emf.ecore.provider.annotation.EAnnotationItemProviderAdapterFactory;
+import org.eclipse.emf.ecore.util.BasicEAnnotationValidator;
+import org.eclipse.emf.edit.domain.EditingDomain;
+import org.eclipse.emf.edit.provider.IItemPropertyDescriptor;
+
+
+/**
+ * An extension for annotations with source <code>http://www.eclipse.org/emf/2002/GenModel</code>.
+ * 
+ * @since 2.14
+ * @see GenModelPackage#eNS_URI
+ */
+public final class GenModelEAnnotationItemProviderAdapterFactory extends EAnnotationItemProviderAdapterFactory
+{
+  protected static final BasicEAnnotationValidator.Assistant ASSISTANT = ((BasicEAnnotationValidator)EAnnotationValidator.Registry.INSTANCE.getEAnnotationValidator(
+    GenModelPackage.eNS_URI)).getAssistant();
+
+  /**
+   * Creates an instance.
+   */
+  public GenModelEAnnotationItemProviderAdapterFactory()
+  {
+    super(GenModelEditPlugin.INSTANCE, ASSISTANT);
+  }
+
+  @Override
+  public boolean isShowInstances(EAnnotation eAnnotation)
+  {
+    return true;
+  }
+
+  @Override
+  public IItemPropertyDescriptor createPropertyDescriptorDecorator(
+    IItemPropertyDescriptor propertyDescriptor,
+    EObject eObject,
+    final String key,
+    final EStructuralFeature eStructuralFeature,
+    final EAnnotation eAnnotation,
+    ResourceLocator resourceLocator,
+    final EditingDomain domain)
+  {
+    return new EAnnotationItemProviderAdapterFactory.ModeledItemPropertyDescriptorDecorator(
+      propertyDescriptor,
+      eObject,
+      key,
+      eStructuralFeature,
+      eAnnotation,
+      resourceLocator,
+      domain,
+      ASSISTANT)
+      {
+        @Override
+        public Collection<?> getChoiceOfValues(Object object)
+        {
+          if (eStructuralFeature == GenModelPackage.Literals.GEN_CLASS__LABEL_FEATURE)
+          {
+            GenClass genClass = (GenClass)this.object;
+            GenFeature labelFeature = genClass.getLabelFeature();
+            List<GenFeature> result = new ArrayList<GenFeature>();
+            EClass modelEClass = (EClass)eAnnotation.getEModelElement();
+            for (EAttribute eAttribute : modelEClass.getEAllAttributes())
+            {
+              if (labelFeature != null && labelFeature.getEcoreFeature() == eAttribute)
+              {
+                result.add(labelFeature);
+              }
+              else
+              {
+                GenFeature genFeature = GenModelFactory.eINSTANCE.createGenFeature();
+                genFeature.setEcoreFeature(eAttribute);
+                result.add(genFeature);
+              }
+            }
+            return result;
+          }
+          else
+          {
+            return super.getChoiceOfValues(object);
+          }
+        }
+      };
+  }
+}
diff --git a/plugins/org.eclipse.emf.codegen.ecore.ui/src/org/eclipse/emf/codegen/ecore/genmodel/provider/GenModelItemProvider.java b/plugins/org.eclipse.emf.codegen.ecore.ui/src/org/eclipse/emf/codegen/ecore/genmodel/provider/GenModelItemProvider.java
index 29b52d0..99386a5 100644
--- a/plugins/org.eclipse.emf.codegen.ecore.ui/src/org/eclipse/emf/codegen/ecore/genmodel/provider/GenModelItemProvider.java
+++ b/plugins/org.eclipse.emf.codegen.ecore.ui/src/org/eclipse/emf/codegen/ecore/genmodel/provider/GenModelItemProvider.java
@@ -149,6 +149,7 @@
       addCleanupPropertyDescriptor(object);
       addOSGiCompatiblePropertyDescriptor(object);
       addEclipsePlatformVersionPropertyDescriptor(object);
+      addModelDocumentationPropertyDescriptor(object);
     }
     return itemPropertyDescriptors;
   }
@@ -1998,6 +1999,7 @@
    * This adds a property descriptor for the Eclipse Platform Version feature.
    * <!-- begin-user-doc -->
    * <!-- end-user-doc -->
+   * @since 2.14
    * @generated
    */
   protected void addEclipsePlatformVersionPropertyDescriptor(Object object)
@@ -2018,6 +2020,30 @@
   }
 
   /**
+   * This adds a property descriptor for the Model Documentation feature.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @since 2.14
+   * @generated
+   */
+  protected void addModelDocumentationPropertyDescriptor(Object object)
+  {
+    itemPropertyDescriptors.add
+      (createItemPropertyDescriptor
+        (((ComposeableAdapterFactory)adapterFactory).getRootAdapterFactory(),
+         getResourceLocator(),
+         getString("_UI_GenModel_modelDocumentation_feature"),
+         getString("_UI_GenModel_modelDocumentation_description"),
+         GenModelPackage.Literals.GEN_MODEL__MODEL_DOCUMENTATION,
+         true,
+         true,
+         false,
+         ItemPropertyDescriptor.GENERIC_VALUE_IMAGE,
+         getString("_UI_AllPropertyCategory"),
+         null));
+  }
+
+  /**
    * This specifies how to implement {@link #getChildren} and is used to deduce an appropriate feature for an
    * {@link org.eclipse.emf.edit.command.AddCommand}, {@link org.eclipse.emf.edit.command.RemoveCommand} or
    * {@link org.eclipse.emf.edit.command.MoveCommand} in {@link #createCommand}.
@@ -2168,6 +2194,7 @@
       case GenModelPackage.GEN_MODEL__CLEANUP:
       case GenModelPackage.GEN_MODEL__OS_GI_COMPATIBLE:
       case GenModelPackage.GEN_MODEL__ECLIPSE_PLATFORM_VERSION:
+      case GenModelPackage.GEN_MODEL__MODEL_DOCUMENTATION:
         fireNotifyChanged(new ViewerNotification(notification, notification.getNotifier(), false, true));
         return;
       case GenModelPackage.GEN_MODEL__GEN_PACKAGES:
diff --git a/plugins/org.eclipse.emf.codegen.ecore.ui/src/org/eclipse/emf/codegen/ecore/genmodel/provider/GenModelItemProviderAdapterFactory.java b/plugins/org.eclipse.emf.codegen.ecore.ui/src/org/eclipse/emf/codegen/ecore/genmodel/provider/GenModelItemProviderAdapterFactory.java
index d83597d..6c026ed 100644
--- a/plugins/org.eclipse.emf.codegen.ecore.ui/src/org/eclipse/emf/codegen/ecore/genmodel/provider/GenModelItemProviderAdapterFactory.java
+++ b/plugins/org.eclipse.emf.codegen.ecore.ui/src/org/eclipse/emf/codegen/ecore/genmodel/provider/GenModelItemProviderAdapterFactory.java
@@ -280,6 +280,31 @@
   }
 
   /**
+   * This keeps track of the one adapter used for all {@link org.eclipse.emf.codegen.ecore.genmodel.GenParameter} instances.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @generated
+   */
+  protected GenParameterItemProvider genParameterItemProvider;
+
+  /**
+   * This creates an adapter for a {@link org.eclipse.emf.codegen.ecore.genmodel.GenParameter}.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @generated
+   */
+  @Override
+  public Adapter createGenParameterAdapter()
+  {
+    if (genParameterItemProvider == null)
+    {
+      genParameterItemProvider = new GenParameterItemProvider(this);
+    }
+
+    return genParameterItemProvider;
+  }
+
+  /**
    * This keeps track of the one adapter used for all {@link org.eclipse.emf.codegen.ecore.genmodel.GenAnnotation} instances.
    * <!-- begin-user-doc -->
    * <!-- end-user-doc -->
@@ -423,6 +448,7 @@
     if (genEnumLiteralItemProvider != null) genEnumLiteralItemProvider.dispose();
     if (genDataTypeItemProvider != null) genDataTypeItemProvider.dispose();
     if (genOperationItemProvider != null) genOperationItemProvider.dispose();
+    if (genParameterItemProvider != null) genParameterItemProvider.dispose();
     if (genAnnotationItemProvider != null) genAnnotationItemProvider.dispose();
   }
 
diff --git a/plugins/org.eclipse.emf.codegen.ecore.ui/src/org/eclipse/emf/codegen/ecore/genmodel/provider/GenOperationItemProvider.java b/plugins/org.eclipse.emf.codegen.ecore.ui/src/org/eclipse/emf/codegen/ecore/genmodel/provider/GenOperationItemProvider.java
index c51e503..80c1f2c 100644
--- a/plugins/org.eclipse.emf.codegen.ecore.ui/src/org/eclipse/emf/codegen/ecore/genmodel/provider/GenOperationItemProvider.java
+++ b/plugins/org.eclipse.emf.codegen.ecore.ui/src/org/eclipse/emf/codegen/ecore/genmodel/provider/GenOperationItemProvider.java
@@ -23,10 +23,9 @@
 import org.eclipse.emf.ecore.EParameter;
 import org.eclipse.emf.edit.provider.ComposeableAdapterFactory;
 import org.eclipse.emf.edit.provider.IItemPropertyDescriptor;
+import org.eclipse.emf.edit.provider.ItemPropertyDescriptor;
 import org.eclipse.emf.edit.provider.ViewerNotification;
 
-// import org.eclipse.emf.edit.provider.ItemPropertyDescriptor;
-
 
 /**
  * This is the item provider adapter for a {@link org.eclipse.emf.codegen.ecore.genmodel.GenOperation} object.
@@ -61,12 +60,38 @@
     {
       super.getPropertyDescriptors(object);
 
+      addDocumentationPropertyDescriptor(object);
       addEcoreOperationPropertyDescriptor(object);
+      addSuppressedVisibilityPropertyDescriptor(object);
     }
     return itemPropertyDescriptors;
   }
 
   /**
+   * This adds a property descriptor for the Documentation feature.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @since 2.14
+   * @generated
+   */
+  protected void addDocumentationPropertyDescriptor(Object object)
+  {
+    itemPropertyDescriptors.add
+      (createItemPropertyDescriptor
+        (((ComposeableAdapterFactory)adapterFactory).getRootAdapterFactory(),
+         getResourceLocator(),
+         getString("_UI_GenTypedElement_documentation_feature"),
+         getString("_UI_GenTypedElement_documentation_description"),
+         GenModelPackage.Literals.GEN_TYPED_ELEMENT__DOCUMENTATION,
+         true,
+         true,
+         false,
+         ItemPropertyDescriptor.GENERIC_VALUE_IMAGE,
+         getString("_UI_ModelPropertyCategory"),
+         null));
+  }
+
+  /**
    * This adds a property descriptor for the Ecore Operation feature.
    * <!-- begin-user-doc -->
    * <!-- end-user-doc -->
@@ -90,6 +115,30 @@
   }
 
   /**
+   * This adds a property descriptor for the Suppressed Visibility feature.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @since 2.14
+   * @generated
+   */
+  protected void addSuppressedVisibilityPropertyDescriptor(Object object)
+  {
+    itemPropertyDescriptors.add
+      (createItemPropertyDescriptor
+        (((ComposeableAdapterFactory)adapterFactory).getRootAdapterFactory(),
+         getResourceLocator(),
+         getString("_UI_GenOperation_suppressedVisibility_feature"),
+         getString("_UI_GenOperation_suppressedVisibility_description"),
+         GenModelPackage.Literals.GEN_OPERATION__SUPPRESSED_VISIBILITY,
+         true,
+         false,
+         false,
+         ItemPropertyDescriptor.BOOLEAN_VALUE_IMAGE,
+         getString("_UI_ModelPropertyCategory"),
+         null));
+  }
+
+  /**
    */
   @Override
   public Object getImage(Object object)
@@ -165,9 +214,11 @@
 
     switch (notification.getFeatureID(GenOperation.class))
     {
+      case GenModelPackage.GEN_OPERATION__DOCUMENTATION:
       case GenModelPackage.GEN_OPERATION__ECORE_OPERATION:
       case GenModelPackage.GEN_OPERATION__GEN_PARAMETERS:
       case GenModelPackage.GEN_OPERATION__GEN_TYPE_PARAMETERS:
+      case GenModelPackage.GEN_OPERATION__SUPPRESSED_VISIBILITY:
         fireNotifyChanged(new ViewerNotification(notification, notification.getNotifier(), false, true));
         return;
     }
diff --git a/plugins/org.eclipse.emf.codegen.ecore.ui/src/org/eclipse/emf/codegen/ecore/genmodel/provider/GenPackageItemProvider.java b/plugins/org.eclipse.emf.codegen.ecore.ui/src/org/eclipse/emf/codegen/ecore/genmodel/provider/GenPackageItemProvider.java
index fb9f9b7..687338a 100644
--- a/plugins/org.eclipse.emf.codegen.ecore.ui/src/org/eclipse/emf/codegen/ecore/genmodel/provider/GenPackageItemProvider.java
+++ b/plugins/org.eclipse.emf.codegen.ecore.ui/src/org/eclipse/emf/codegen/ecore/genmodel/provider/GenPackageItemProvider.java
@@ -87,6 +87,7 @@
       addFileExtensionsPropertyDescriptor(object);
       addEcorePackagePropertyDescriptor(object);
       addPublicationLocationPropertyDescriptor(object);
+      addDocumentationPropertyDescriptor(object);
     }
     return itemPropertyDescriptors;
   }
@@ -644,6 +645,30 @@
   }
 
   /**
+   * This adds a property descriptor for the Documentation feature.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @since 2.14
+   * @generated
+   */
+  protected void addDocumentationPropertyDescriptor(Object object)
+  {
+    itemPropertyDescriptors.add
+      (createItemPropertyDescriptor
+        (((ComposeableAdapterFactory)adapterFactory).getRootAdapterFactory(),
+         getResourceLocator(),
+         getString("_UI_GenPackage_documentation_feature"),
+         getString("_UI_GenPackage_documentation_description"),
+         GenModelPackage.Literals.GEN_PACKAGE__DOCUMENTATION,
+         true,
+         true,
+         false,
+         ItemPropertyDescriptor.GENERIC_VALUE_IMAGE,
+         getString("_UI_ModelPropertyCategory"),
+         null));
+  }
+
+  /**
    * <!-- begin-user-doc -->
    * <!-- end-user-doc -->
    * @generated
@@ -753,6 +778,7 @@
       case GenModelPackage.GEN_PACKAGE__FILE_EXTENSIONS:
       case GenModelPackage.GEN_PACKAGE__ECORE_PACKAGE:
       case GenModelPackage.GEN_PACKAGE__PUBLICATION_LOCATION:
+      case GenModelPackage.GEN_PACKAGE__DOCUMENTATION:
         fireNotifyChanged(new ViewerNotification(notification, notification.getNotifier(), false, true));
         return;
       case GenModelPackage.GEN_PACKAGE__GEN_ENUMS:
diff --git a/plugins/org.eclipse.emf.codegen.ecore.ui/src/org/eclipse/emf/codegen/ecore/genmodel/provider/GenParameterItemProvider.java b/plugins/org.eclipse.emf.codegen.ecore.ui/src/org/eclipse/emf/codegen/ecore/genmodel/provider/GenParameterItemProvider.java
new file mode 100644
index 0000000..b6de152
--- /dev/null
+++ b/plugins/org.eclipse.emf.codegen.ecore.ui/src/org/eclipse/emf/codegen/ecore/genmodel/provider/GenParameterItemProvider.java
@@ -0,0 +1,147 @@
+/**
+ * Copyright (c) 2017 Eclipse contributors and others.
+ * All rights reserved.   This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.eclipse.emf.codegen.ecore.genmodel.provider;
+
+
+import java.util.List;
+
+import org.eclipse.emf.codegen.ecore.genmodel.GenModelPackage;
+import org.eclipse.emf.codegen.ecore.genmodel.GenParameter;
+
+import org.eclipse.emf.common.notify.AdapterFactory;
+import org.eclipse.emf.common.notify.Notification;
+
+import org.eclipse.emf.edit.provider.ComposeableAdapterFactory;
+import org.eclipse.emf.edit.provider.IItemPropertyDescriptor;
+import org.eclipse.emf.edit.provider.ItemPropertyDescriptor;
+import org.eclipse.emf.edit.provider.ViewerNotification;
+
+/**
+ * This is the item provider adapter for a {@link org.eclipse.emf.codegen.ecore.genmodel.GenParameter} object.
+ * <!-- begin-user-doc -->
+ * @since 2.14
+ * <!-- end-user-doc -->
+ * @generated
+ */
+public class GenParameterItemProvider extends GenBaseItemProvider
+{
+  /**
+   * This constructs an instance from a factory and a notifier.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @generated
+   */
+  public GenParameterItemProvider(AdapterFactory adapterFactory)
+  {
+    super(adapterFactory);
+  }
+
+  /**
+   * This returns the property descriptors for the adapted class.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @generated
+   */
+  @Override
+  public List<IItemPropertyDescriptor> getPropertyDescriptors(Object object)
+  {
+    if (itemPropertyDescriptors == null)
+    {
+      super.getPropertyDescriptors(object);
+
+      addDocumentationPropertyDescriptor(object);
+      addEcoreParameterPropertyDescriptor(object);
+    }
+    return itemPropertyDescriptors;
+  }
+
+  /**
+   * This adds a property descriptor for the Documentation feature.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @generated NOT
+   */
+  protected void addDocumentationPropertyDescriptor(Object object)
+  {
+    itemPropertyDescriptors.add
+      (createItemPropertyDescriptor
+        (((ComposeableAdapterFactory)adapterFactory).getRootAdapterFactory(),
+         getResourceLocator(),
+         getString("_UI_GenTypedElement_documentation_feature"),
+         getString("_UI_GenParameter_documentation_description"),
+         GenModelPackage.Literals.GEN_TYPED_ELEMENT__DOCUMENTATION,
+         true,
+         true,
+         false,
+         ItemPropertyDescriptor.GENERIC_VALUE_IMAGE,
+         getString("_UI_AllPropertyCategory"),
+         null));
+  }
+
+  /**
+   * This adds a property descriptor for the Ecore Parameter feature.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @generated
+   */
+  protected void addEcoreParameterPropertyDescriptor(Object object)
+  {
+    itemPropertyDescriptors.add
+      (createItemPropertyDescriptor
+        (((ComposeableAdapterFactory)adapterFactory).getRootAdapterFactory(),
+         getResourceLocator(),
+         getString("_UI_GenParameter_ecoreParameter_feature"),
+         getString("_UI_PropertyDescriptor_description", "_UI_GenParameter_ecoreParameter_feature", "_UI_GenParameter_type"),
+         GenModelPackage.Literals.GEN_PARAMETER__ECORE_PARAMETER,
+         false,
+         false,
+         false,
+         null,
+         getString("_UI_EcorePropertyCategory"),
+         null));
+  }
+
+  /**
+   * This returns the label text for the adapted class.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @generated
+   */
+  @Override
+  public String getText(Object object)
+  {
+    String label = crop(((GenParameter)object).getDocumentation());
+    return label == null || label.length() == 0 ?
+      getString("_UI_GenParameter_type") :
+      getString("_UI_GenParameter_type") + " " + label;
+  }
+
+
+  /**
+   * This handles model notifications by calling {@link #updateChildren} to update any cached
+   * children and by creating a viewer notification, which it passes to {@link #fireNotifyChanged}.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @generated
+   */
+  @Override
+  public void notifyChanged(Notification notification)
+  {
+    updateChildren(notification);
+
+    switch (notification.getFeatureID(GenParameter.class))
+    {
+      case GenModelPackage.GEN_PARAMETER__DOCUMENTATION:
+      case GenModelPackage.GEN_PARAMETER__ECORE_PARAMETER:
+        fireNotifyChanged(new ViewerNotification(notification, notification.getNotifier(), false, true));
+        return;
+    }
+    super.notifyChanged(notification);
+  }
+
+}
diff --git a/plugins/org.eclipse.emf.codegen.ecore/model/GenModel.ecore b/plugins/org.eclipse.emf.codegen.ecore/model/GenModel.ecore
index b5f01ad..9af4760 100644
--- a/plugins/org.eclipse.emf.codegen.ecore/model/GenModel.ecore
+++ b/plugins/org.eclipse.emf.codegen.ecore/model/GenModel.ecore
@@ -135,6 +135,16 @@
         eType="#//GenEclipsePlatformVersion" unsettable="true">
       <eAnnotations source="http://www.eclipse.org/emf/2002/GenModel">
         <details key="documentation" value="@since 2.14"/>
+        <details key="suppressedIsSetVisibility" value="true"/>
+        <details key="suppressedUnsetVisibility" value="true"/>
+      </eAnnotations>
+    </eStructuralFeatures>
+    <eStructuralFeatures xsi:type="ecore:EAttribute" name="modelDocumentation" eType="ecore:EDataType ../../org.eclipse.emf.ecore/model/Ecore.ecore#//EString"
+        unsettable="true">
+      <eAnnotations source="http://www.eclipse.org/emf/2002/GenModel">
+        <details key="documentation" value="@since 2.14"/>
+        <details key="suppressedIsSetVisibility" value="true"/>
+        <details key="suppressedUnsetVisibility" value="true"/>
       </eAnnotations>
     </eStructuralFeatures>
   </eClassifiers>
@@ -193,6 +203,14 @@
         eType="#//GenClassifier" changeable="false" volatile="true" transient="true"
         resolveProxies="false" eOpposite="#//GenClassifier/genPackage"/>
     <eStructuralFeatures xsi:type="ecore:EAttribute" name="publicationLocation" eType="ecore:EDataType ../../org.eclipse.emf.ecore/model/Ecore.ecore#//EString"/>
+    <eStructuralFeatures xsi:type="ecore:EAttribute" name="documentation" eType="ecore:EDataType ../../org.eclipse.emf.ecore/model/Ecore.ecore#//EString"
+        unsettable="true">
+      <eAnnotations source="http://www.eclipse.org/emf/2002/GenModel">
+        <details key="documentation" value="@since 2.14"/>
+        <details key="suppressedIsSetVisibility" value="true"/>
+        <details key="suppressedUnsetVisibility" value="true"/>
+      </eAnnotations>
+    </eStructuralFeatures>
   </eClassifiers>
   <eClassifiers xsi:type="ecore:EClass" name="GenClass" eSuperTypes="#//GenClassifier">
     <eStructuralFeatures xsi:type="ecore:EAttribute" name="provider" eType="#//GenProviderKind"/>
@@ -224,6 +242,42 @@
         eType="#//GenClass" transient="true" eOpposite="#//GenClass/genFeatures"/>
     <eStructuralFeatures xsi:type="ecore:EReference" name="ecoreFeature" lowerBound="1"
         eType="ecore:EClass ../../org.eclipse.emf.ecore/model/Ecore.ecore#//EStructuralFeature"/>
+    <eStructuralFeatures xsi:type="ecore:EAttribute" name="suppressedGetVisibility"
+        eType="ecore:EDataType ../../org.eclipse.emf.ecore/model/Ecore.ecore#//EBoolean"
+        unsettable="true">
+      <eAnnotations source="http://www.eclipse.org/emf/2002/GenModel">
+        <details key="documentation" value="@since 2.14"/>
+        <details key="suppressedIsSetVisibility" value="true"/>
+        <details key="suppressedUnsetVisibility" value="true"/>
+      </eAnnotations>
+    </eStructuralFeatures>
+    <eStructuralFeatures xsi:type="ecore:EAttribute" name="suppressedSetVisibility"
+        eType="ecore:EDataType ../../org.eclipse.emf.ecore/model/Ecore.ecore#//EBoolean"
+        unsettable="true">
+      <eAnnotations source="http://www.eclipse.org/emf/2002/GenModel">
+        <details key="documentation" value="@since 2.14"/>
+        <details key="suppressedIsSetVisibility" value="true"/>
+        <details key="suppressedUnsetVisibility" value="true"/>
+      </eAnnotations>
+    </eStructuralFeatures>
+    <eStructuralFeatures xsi:type="ecore:EAttribute" name="suppressedIsSetVisibility"
+        eType="ecore:EDataType ../../org.eclipse.emf.ecore/model/Ecore.ecore#//EBoolean"
+        unsettable="true">
+      <eAnnotations source="http://www.eclipse.org/emf/2002/GenModel">
+        <details key="documentation" value="@since 2.14"/>
+        <details key="suppressedIsSetVisibility" value="true"/>
+        <details key="suppressedUnsetVisibility" value="true"/>
+      </eAnnotations>
+    </eStructuralFeatures>
+    <eStructuralFeatures xsi:type="ecore:EAttribute" name="suppressedUnsetVisibility"
+        eType="ecore:EDataType ../../org.eclipse.emf.ecore/model/Ecore.ecore#//EBoolean"
+        unsettable="true">
+      <eAnnotations source="http://www.eclipse.org/emf/2002/GenModel">
+        <details key="documentation" value="@since 2.14"/>
+        <details key="suppressedIsSetVisibility" value="true"/>
+        <details key="suppressedUnsetVisibility" value="true"/>
+      </eAnnotations>
+    </eStructuralFeatures>
   </eClassifiers>
   <eClassifiers xsi:type="ecore:EClass" name="GenBase" abstract="true">
     <eOperations name="getGenAnnotation" eType="#//GenAnnotation">
@@ -248,6 +302,14 @@
         eType="#//GenEnum" transient="true" eOpposite="#//GenEnum/genEnumLiterals"/>
     <eStructuralFeatures xsi:type="ecore:EReference" name="ecoreEnumLiteral" lowerBound="1"
         eType="ecore:EClass ../../org.eclipse.emf.ecore/model/Ecore.ecore#//EEnumLiteral"/>
+    <eStructuralFeatures xsi:type="ecore:EAttribute" name="documentation" eType="ecore:EDataType ../../org.eclipse.emf.ecore/model/Ecore.ecore#//EString"
+        unsettable="true">
+      <eAnnotations source="http://www.eclipse.org/emf/2002/GenModel">
+        <details key="documentation" value="@since 2.14"/>
+        <details key="suppressedIsSetVisibility" value="true"/>
+        <details key="suppressedUnsetVisibility" value="true"/>
+      </eAnnotations>
+    </eStructuralFeatures>
   </eClassifiers>
   <eClassifiers xsi:type="ecore:EClass" name="GenClassifier" abstract="true" eSuperTypes="#//GenBase">
     <eStructuralFeatures xsi:type="ecore:EReference" name="genPackage" lowerBound="1"
@@ -255,6 +317,14 @@
         resolveProxies="false" eOpposite="#//GenPackage/genClassifiers"/>
     <eStructuralFeatures xsi:type="ecore:EReference" name="genTypeParameters" upperBound="-1"
         eType="#//GenTypeParameter" containment="true"/>
+    <eStructuralFeatures xsi:type="ecore:EAttribute" name="documentation" eType="ecore:EDataType ../../org.eclipse.emf.ecore/model/Ecore.ecore#//EString"
+        unsettable="true">
+      <eAnnotations source="http://www.eclipse.org/emf/2002/GenModel">
+        <details key="documentation" value="@since 2.14"/>
+        <details key="suppressedIsSetVisibility" value="true"/>
+        <details key="suppressedUnsetVisibility" value="true"/>
+      </eAnnotations>
+    </eStructuralFeatures>
   </eClassifiers>
   <eClassifiers xsi:type="ecore:EClass" name="GenDataType" eSuperTypes="#//GenClassifier">
     <eStructuralFeatures xsi:type="ecore:EReference" name="ecoreDataType" lowerBound="1"
@@ -269,6 +339,14 @@
         eType="#//GenParameter" containment="true" eOpposite="#//GenParameter/genOperation"/>
     <eStructuralFeatures xsi:type="ecore:EReference" name="genTypeParameters" upperBound="-1"
         eType="#//GenTypeParameter" containment="true"/>
+    <eStructuralFeatures xsi:type="ecore:EAttribute" name="suppressedVisibility" eType="ecore:EDataType ../../org.eclipse.emf.ecore/model/Ecore.ecore#//EBoolean"
+        unsettable="true">
+      <eAnnotations source="http://www.eclipse.org/emf/2002/GenModel">
+        <details key="documentation" value="@since 2.14"/>
+        <details key="suppressedIsSetVisibility" value="true"/>
+        <details key="suppressedUnsetVisibility" value="true"/>
+      </eAnnotations>
+    </eStructuralFeatures>
   </eClassifiers>
   <eClassifiers xsi:type="ecore:EClass" name="GenParameter" eSuperTypes="#//GenTypedElement">
     <eStructuralFeatures xsi:type="ecore:EReference" name="genOperation" lowerBound="1"
@@ -292,7 +370,16 @@
     <eLiterals name="XMI" value="2"/>
     <eLiterals name="XML" value="3"/>
   </eClassifiers>
-  <eClassifiers xsi:type="ecore:EClass" name="GenTypedElement" abstract="true" eSuperTypes="#//GenBase"/>
+  <eClassifiers xsi:type="ecore:EClass" name="GenTypedElement" abstract="true" eSuperTypes="#//GenBase">
+    <eStructuralFeatures xsi:type="ecore:EAttribute" name="documentation" eType="ecore:EDataType ../../org.eclipse.emf.ecore/model/Ecore.ecore#//EString"
+        unsettable="true">
+      <eAnnotations source="http://www.eclipse.org/emf/2002/GenModel">
+        <details key="documentation" value="@since 2.14"/>
+        <details key="suppressedIsSetVisibility" value="true"/>
+        <details key="suppressedUnsetVisibility" value="true"/>
+      </eAnnotations>
+    </eStructuralFeatures>
+  </eClassifiers>
   <eClassifiers xsi:type="ecore:EEnum" name="GenDelegationKind">
     <eLiterals name="None"/>
     <eLiterals name="Reflective" value="1"/>
@@ -327,6 +414,14 @@
   <eClassifiers xsi:type="ecore:EClass" name="GenTypeParameter" eSuperTypes="#//GenBase">
     <eStructuralFeatures xsi:type="ecore:EReference" name="ecoreTypeParameter" lowerBound="1"
         eType="ecore:EClass ../../org.eclipse.emf.ecore/model/Ecore.ecore#//ETypeParameter"/>
+    <eStructuralFeatures xsi:type="ecore:EAttribute" name="documentation" eType="ecore:EDataType ../../org.eclipse.emf.ecore/model/Ecore.ecore#//EString"
+        unsettable="true">
+      <eAnnotations source="http://www.eclipse.org/emf/2002/GenModel">
+        <details key="documentation" value="@since 2.14"/>
+        <details key="suppressedIsSetVisibility" value="true"/>
+        <details key="suppressedUnsetVisibility" value="true"/>
+      </eAnnotations>
+    </eStructuralFeatures>
   </eClassifiers>
   <eClassifiers xsi:type="ecore:EEnum" name="GenRuntimeVersion">
     <eLiterals name="EMF22" literal="2.2"/>
diff --git a/plugins/org.eclipse.emf.codegen.ecore/model/GenModel.genmodel b/plugins/org.eclipse.emf.codegen.ecore/model/GenModel.genmodel
index a277d1e..bf26e96 100644
--- a/plugins/org.eclipse.emf.codegen.ecore/model/GenModel.genmodel
+++ b/plugins/org.eclipse.emf.codegen.ecore/model/GenModel.genmodel
@@ -248,6 +248,8 @@
           ecoreFeature="ecore:EAttribute GenModel.ecore#//GenModel/oSGiCompatible"/>
       <genFeatures createChild="false" propertyCategory="All" propertyDescription="The version of the Eclipse runtime against which to target the generated code for an RCP or IDE runtime platform"
           ecoreFeature="ecore:EAttribute GenModel.ecore#//GenModel/eclipsePlatformVersion"/>
+      <genFeatures createChild="false" propertyCategory="All" propertyDescription="The Javadoc documentation to generate for the model-level artifacts such as plug-in classes, including any @since or @deprecated tags"
+          propertyMultiLine="true" ecoreFeature="ecore:EAttribute GenModel.ecore#//GenModel/modelDocumentation"/>
     </genClasses>
     <genClasses image="false" ecoreClass="GenModel.ecore#//GenPackage">
       <genFeatures createChild="false" propertyCategory="All" propertyDescription="The prefix for names of several packaged-related classes, including package, factory, switch, and adapter factory"
@@ -304,6 +306,8 @@
       <genFeatures property="None" notify="false" createChild="false" ecoreFeature="ecore:EReference GenModel.ecore#//GenPackage/genClassifiers"/>
       <genFeatures createChild="false" propertyCategory="Model" propertyDescription="The workspace-relative location at which to generate a published version of the Ecore model resource"
           ecoreFeature="ecore:EAttribute GenModel.ecore#//GenPackage/publicationLocation"/>
+      <genFeatures createChild="false" propertyCategory="Model" propertyDescription="The Javadoc to be generated, including any @since or @deprecated tags"
+          propertyMultiLine="true" ecoreFeature="ecore:EAttribute GenModel.ecore#//GenPackage/documentation"/>
     </genClasses>
     <genClasses image="false" ecoreClass="GenModel.ecore#//GenClass">
       <genFeatures createChild="false" propertyCategory="Edit" propertyDescription="Whether to generate an item provider and which pattern to use"
@@ -342,6 +346,14 @@
       <genFeatures property="Readonly" createChild="false" propertyCategory="Ecore"
           propertyDescription="The Ecore model element for this structural feature"
           ecoreFeature="ecore:EReference GenModel.ecore#//GenFeature/ecoreFeature"/>
+      <genFeatures createChild="false" propertyCategory="Model" propertyDescription="Whether to suppress the generated get accessor from the interface"
+          ecoreFeature="ecore:EAttribute GenModel.ecore#//GenFeature/suppressedGetVisibility"/>
+      <genFeatures createChild="false" propertyCategory="Model" propertyDescription="Whether to suppress the generated set accessor from the interface"
+          ecoreFeature="ecore:EAttribute GenModel.ecore#//GenFeature/suppressedSetVisibility"/>
+      <genFeatures createChild="false" propertyCategory="Model" propertyDescription="Whether to suppress the generated is-set accessor from the interface"
+          ecoreFeature="ecore:EAttribute GenModel.ecore#//GenFeature/suppressedIsSetVisibility"/>
+      <genFeatures createChild="false" propertyCategory="Model" propertyDescription="Whether to suppress the generated unset accessor from the interface"
+          ecoreFeature="ecore:EAttribute GenModel.ecore#//GenFeature/suppressedUnsetVisibility"/>
     </genClasses>
     <genClasses image="false" ecoreClass="GenModel.ecore#//GenBase">
       <genFeatures property="None" children="true" createChild="true" ecoreFeature="ecore:EReference GenModel.ecore#//GenBase/genAnnotations"/>
@@ -361,10 +373,14 @@
       <genFeatures property="Readonly" createChild="false" propertyCategory="Ecore"
           propertyDescription="The Ecore model element for this enumerated type literal"
           ecoreFeature="ecore:EReference GenModel.ecore#//GenEnumLiteral/ecoreEnumLiteral"/>
+      <genFeatures createChild="false" propertyCategory="Model" propertyDescription="The Javadoc to be generated, including any @since or @deprecated tags"
+          propertyMultiLine="true" ecoreFeature="ecore:EAttribute GenModel.ecore#//GenEnumLiteral/documentation"/>
     </genClasses>
     <genClasses provider="None" image="false" ecoreClass="GenModel.ecore#//GenClassifier">
       <genFeatures property="None" createChild="false" ecoreFeature="ecore:EReference GenModel.ecore#//GenClassifier/genPackage"/>
       <genFeatures property="None" createChild="false" ecoreFeature="ecore:EReference GenModel.ecore#//GenClassifier/genTypeParameters"/>
+      <genFeatures createChild="false" propertyCategory="Model" propertyDescription="The Javadoc to be generated, including any @since or @deprecated tags"
+          propertyMultiLine="true" ecoreFeature="ecore:EAttribute GenModel.ecore#//GenClassifier/documentation"/>
     </genClasses>
     <genClasses image="false" ecoreClass="GenModel.ecore#//GenDataType">
       <genFeatures property="Readonly" createChild="false" propertyCategory="Ecore"
@@ -376,13 +392,18 @@
           propertyDescription="The Ecore model element for this operation" ecoreFeature="ecore:EReference GenModel.ecore#//GenOperation/ecoreOperation"/>
       <genFeatures property="None" createChild="false" ecoreFeature="ecore:EReference GenModel.ecore#//GenOperation/genParameters"/>
       <genFeatures property="None" createChild="false" ecoreFeature="ecore:EReference GenModel.ecore#//GenOperation/genTypeParameters"/>
+      <genFeatures createChild="false" propertyCategory="Model" propertyDescription="Whether to suppress the generated method from the interface"
+          ecoreFeature="ecore:EAttribute GenModel.ecore#//GenOperation/suppressedVisibility"/>
     </genClasses>
-    <genClasses provider="None" image="false" ecoreClass="GenModel.ecore#//GenParameter">
+    <genClasses image="false" ecoreClass="GenModel.ecore#//GenParameter">
       <genFeatures property="None" notify="false" createChild="false" ecoreFeature="ecore:EReference GenModel.ecore#//GenParameter/genOperation"/>
       <genFeatures property="Readonly" createChild="false" propertyCategory="Ecore"
           ecoreFeature="ecore:EReference GenModel.ecore#//GenParameter/ecoreParameter"/>
     </genClasses>
-    <genClasses provider="None" image="false" ecoreClass="GenModel.ecore#//GenTypedElement"/>
+    <genClasses provider="None" image="false" ecoreClass="GenModel.ecore#//GenTypedElement">
+      <genFeatures createChild="false" propertyCategory="Model" propertyDescription="The Javadoc to be generated, including any @since or @deprecated tags"
+          propertyMultiLine="true" ecoreFeature="ecore:EAttribute GenModel.ecore#//GenTypedElement/documentation"/>
+    </genClasses>
     <genClasses ecoreClass="GenModel.ecore#//GenAnnotation">
       <genFeatures createChild="false" ecoreFeature="ecore:EAttribute GenModel.ecore#//GenAnnotation/source"/>
       <genFeatures property="None" children="true" createChild="true" ecoreFeature="ecore:EReference GenModel.ecore#//GenAnnotation/details"/>
@@ -392,6 +413,8 @@
     </genClasses>
     <genClasses provider="None" image="false" ecoreClass="GenModel.ecore#//GenTypeParameter">
       <genFeatures notify="false" createChild="false" propertySortChoices="true" ecoreFeature="ecore:EReference GenModel.ecore#//GenTypeParameter/ecoreTypeParameter"/>
+      <genFeatures createChild="false" propertyCategory="Model" propertyDescription="The Javadoc to be generated"
+          propertyMultiLine="true" ecoreFeature="ecore:EAttribute GenModel.ecore#//GenTypeParameter/documentation"/>
     </genClasses>
   </genPackages>
 </genmodel:GenModel>
diff --git a/plugins/org.eclipse.emf.codegen.ecore/plugin.properties b/plugins/org.eclipse.emf.codegen.ecore/plugin.properties
index 484ed09..9058eae 100644
--- a/plugins/org.eclipse.emf.codegen.ecore/plugin.properties
+++ b/plugins/org.eclipse.emf.codegen.ecore/plugin.properties
@@ -109,3 +109,6 @@
 _UI_GenEnumNoEcoreDataType_diagnostic = A GenEnum must not have ''{0}'' set as its Ecore data type
 _UI_WellFormedPath_diagnostic = The path ''{0}'' must contain at least two valid segments to denote a workspace folder; {1}
 _UI_BadCharacterInPath_message = {0} is an invalid character in a path
+
+_UI_ValidGenModelAnnotationLocation_substitution = an Ecore named element
+_UI_InvalidAnnotationLabelEntryValue_diagnostic = The value ''{0}'' does not specify the name of an attribute of the annotation''s containing class
diff --git a/plugins/org.eclipse.emf.codegen.ecore/plugin.xml b/plugins/org.eclipse.emf.codegen.ecore/plugin.xml
index b361c4a..20b1e80 100644
--- a/plugins/org.eclipse.emf.codegen.ecore/plugin.xml
+++ b/plugins/org.eclipse.emf.codegen.ecore/plugin.xml
@@ -13,6 +13,14 @@
             class="org.eclipse.emf.codegen.ecore.genmodel.GenModelPackage" genModel="model/GenModel.genmodel"/>
    </extension>
 
+   <extension
+         point="org.eclipse.emf.ecore.annotation_validator">
+      <validator
+            uri="http://www.eclipse.org/emf/2002/GenModel"
+            class="org.eclipse.emf.codegen.ecore.genmodel.util.GenModelAnnotatonValidator">
+      </validator>
+   </extension>
+
    <!--
    <extension point="org.eclipse.emf.ecore.content_parser">
       <parser
diff --git a/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/GenClassifier.java b/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/GenClassifier.java
index dec82a0..ef3af1b 100644
--- a/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/GenClassifier.java
+++ b/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/GenClassifier.java
@@ -28,6 +28,7 @@
  * <ul>
  *   <li>{@link org.eclipse.emf.codegen.ecore.genmodel.GenClassifier#getGenPackage <em>Gen Package</em>}</li>
  *   <li>{@link org.eclipse.emf.codegen.ecore.genmodel.GenClassifier#getGenTypeParameters <em>Gen Type Parameters</em>}</li>
+ *   <li>{@link org.eclipse.emf.codegen.ecore.genmodel.GenClassifier#getDocumentation <em>Documentation</em>}</li>
  * </ul>
  *
  * @see org.eclipse.emf.codegen.ecore.genmodel.GenModelPackage#getGenClassifier()
@@ -64,6 +65,32 @@
    */
   EList<GenTypeParameter> getGenTypeParameters();
 
+  /**
+   * Returns the value of the '<em><b>Documentation</b></em>' attribute.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * <!-- begin-model-doc -->
+   * @since 2.14
+   * <!-- end-model-doc -->
+   * @return the value of the '<em>Documentation</em>' attribute.
+   * @see #setDocumentation(String)
+   * @see org.eclipse.emf.codegen.ecore.genmodel.GenModelPackage#getGenClassifier_Documentation()
+   * @model unsettable="true" suppressedIsSetVisibility="true" suppressedUnsetVisibility="true"
+   * @generated
+   */
+  String getDocumentation();
+
+  /**
+   * Sets the value of the '{@link org.eclipse.emf.codegen.ecore.genmodel.GenClassifier#getDocumentation <em>Documentation</em>}' attribute.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @param value the new value of the '<em>Documentation</em>' attribute.
+   * @see #getDocumentation()
+   * @since 2.14
+   * @generated
+   */
+  void setDocumentation(String value);
+
   EClassifier getEcoreClassifier();
   String getImportedMetaType();
   String getMetaType();
diff --git a/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/GenEnumLiteral.java b/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/GenEnumLiteral.java
index c14ae13..acc8b19 100644
--- a/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/GenEnumLiteral.java
+++ b/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/GenEnumLiteral.java
@@ -25,6 +25,7 @@
  * <ul>
  *   <li>{@link org.eclipse.emf.codegen.ecore.genmodel.GenEnumLiteral#getGenEnum <em>Gen Enum</em>}</li>
  *   <li>{@link org.eclipse.emf.codegen.ecore.genmodel.GenEnumLiteral#getEcoreEnumLiteral <em>Ecore Enum Literal</em>}</li>
+ *   <li>{@link org.eclipse.emf.codegen.ecore.genmodel.GenEnumLiteral#getDocumentation <em>Documentation</em>}</li>
  * </ul>
  *
  * @see org.eclipse.emf.codegen.ecore.genmodel.GenModelPackage#getGenEnumLiteral()
@@ -79,6 +80,32 @@
    */
   void setEcoreEnumLiteral(EEnumLiteral value);
 
+  /**
+   * Returns the value of the '<em><b>Documentation</b></em>' attribute.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * <!-- begin-model-doc -->
+   * @since 2.14
+   * <!-- end-model-doc -->
+   * @return the value of the '<em>Documentation</em>' attribute.
+   * @see #setDocumentation(String)
+   * @see org.eclipse.emf.codegen.ecore.genmodel.GenModelPackage#getGenEnumLiteral_Documentation()
+   * @model unsettable="true" suppressedIsSetVisibility="true" suppressedUnsetVisibility="true"
+   * @generated
+   */
+  String getDocumentation();
+
+  /**
+   * Sets the value of the '{@link org.eclipse.emf.codegen.ecore.genmodel.GenEnumLiteral#getDocumentation <em>Documentation</em>}' attribute.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @param value the new value of the '<em>Documentation</em>' attribute.
+   * @see #getDocumentation()
+   * @since 2.14
+   * @generated
+   */
+  void setDocumentation(String value);
+
   String getName();
   String getCapName();
   int getValue();
diff --git a/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/GenFeature.java b/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/GenFeature.java
index abec411..453059e 100644
--- a/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/GenFeature.java
+++ b/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/GenFeature.java
@@ -37,6 +37,10 @@
  *   <li>{@link org.eclipse.emf.codegen.ecore.genmodel.GenFeature#isPropertySortChoices <em>Property Sort Choices</em>}</li>
  *   <li>{@link org.eclipse.emf.codegen.ecore.genmodel.GenFeature#getGenClass <em>Gen Class</em>}</li>
  *   <li>{@link org.eclipse.emf.codegen.ecore.genmodel.GenFeature#getEcoreFeature <em>Ecore Feature</em>}</li>
+ *   <li>{@link org.eclipse.emf.codegen.ecore.genmodel.GenFeature#isSuppressedGetVisibility <em>Suppressed Get Visibility</em>}</li>
+ *   <li>{@link org.eclipse.emf.codegen.ecore.genmodel.GenFeature#isSuppressedSetVisibility <em>Suppressed Set Visibility</em>}</li>
+ *   <li>{@link org.eclipse.emf.codegen.ecore.genmodel.GenFeature#isSuppressedIsSetVisibility <em>Suppressed Is Set Visibility</em>}</li>
+ *   <li>{@link org.eclipse.emf.codegen.ecore.genmodel.GenFeature#isSuppressedUnsetVisibility <em>Suppressed Unset Visibility</em>}</li>
  * </ul>
  *
  * @see org.eclipse.emf.codegen.ecore.genmodel.GenModelPackage#getGenFeature()
@@ -398,10 +402,57 @@
   String getCreateChildValueLiteral();
 
   boolean isSuppressedGetVisibility();
+
+  /**
+   * Sets the value of the '{@link org.eclipse.emf.codegen.ecore.genmodel.GenFeature#isSuppressedGetVisibility <em>Suppressed Get Visibility</em>}' attribute.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @param value the new value of the '<em>Suppressed Get Visibility</em>' attribute.
+   * @see #isSuppressedGetVisibility()
+   * @since 2.14
+   * @generated
+   */
+  void setSuppressedGetVisibility(boolean value);
+
   boolean isSuppressedSetVisibility();
+
+  /**
+   * Sets the value of the '{@link org.eclipse.emf.codegen.ecore.genmodel.GenFeature#isSuppressedSetVisibility <em>Suppressed Set Visibility</em>}' attribute.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @param value the new value of the '<em>Suppressed Set Visibility</em>' attribute.
+   * @see #isSuppressedSetVisibility()
+   * @since 2.14
+   * @generated
+   */
+  void setSuppressedSetVisibility(boolean value);
+
   boolean isSuppressedIsSetVisibility();
+
+  /**
+   * Sets the value of the '{@link org.eclipse.emf.codegen.ecore.genmodel.GenFeature#isSuppressedIsSetVisibility <em>Suppressed Is Set Visibility</em>}' attribute.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @param value the new value of the '<em>Suppressed Is Set Visibility</em>' attribute.
+   * @see #isSuppressedIsSetVisibility()
+   * @since 2.14
+   * @generated
+   */
+  void setSuppressedIsSetVisibility(boolean value);
+
   boolean isSuppressedUnsetVisibility();
-  
+
+  /**
+   * Sets the value of the '{@link org.eclipse.emf.codegen.ecore.genmodel.GenFeature#isSuppressedUnsetVisibility <em>Suppressed Unset Visibility</em>}' attribute.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @param value the new value of the '<em>Suppressed Unset Visibility</em>' attribute.
+   * @see #isSuppressedUnsetVisibility()
+   * @since 2.14
+   * @generated
+   */
+  void setSuppressedUnsetVisibility(boolean value);
+
   void initialize(EStructuralFeature eFeature);
 
   //
diff --git a/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/GenModel.java b/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/GenModel.java
index 172fb6b..ede520a 100644
--- a/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/GenModel.java
+++ b/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/GenModel.java
@@ -130,6 +130,7 @@
  *   <li>{@link org.eclipse.emf.codegen.ecore.genmodel.GenModel#isCleanup <em>Cleanup</em>}</li>
  *   <li>{@link org.eclipse.emf.codegen.ecore.genmodel.GenModel#isOSGiCompatible <em>OS Gi Compatible</em>}</li>
  *   <li>{@link org.eclipse.emf.codegen.ecore.genmodel.GenModel#getEclipsePlatformVersion <em>Eclipse Platform Version</em>}</li>
+ *   <li>{@link org.eclipse.emf.codegen.ecore.genmodel.GenModel#getModelDocumentation <em>Model Documentation</em>}</li>
  * </ul>
  *
  * @see org.eclipse.emf.codegen.ecore.genmodel.GenModelPackage#getGenModel()
@@ -2305,11 +2306,9 @@
    * <!-- end-model-doc -->
    * @return the value of the '<em>Eclipse Platform Version</em>' attribute.
    * @see org.eclipse.emf.codegen.ecore.genmodel.GenEclipsePlatformVersion
-   * @see #isSetEclipsePlatformVersion()
-   * @see #unsetEclipsePlatformVersion()
    * @see #setEclipsePlatformVersion(GenEclipsePlatformVersion)
    * @see org.eclipse.emf.codegen.ecore.genmodel.GenModelPackage#getGenModel_EclipsePlatformVersion()
-   * @model unsettable="true"
+   * @model unsettable="true" suppressedIsSetVisibility="true" suppressedUnsetVisibility="true"
    * @generated
    */
   GenEclipsePlatformVersion getEclipsePlatformVersion();
@@ -2320,8 +2319,6 @@
    * <!-- end-user-doc -->
    * @param value the new value of the '<em>Eclipse Platform Version</em>' attribute.
    * @see org.eclipse.emf.codegen.ecore.genmodel.GenEclipsePlatformVersion
-   * @see #isSetEclipsePlatformVersion()
-   * @see #unsetEclipsePlatformVersion()
    * @see #getEclipsePlatformVersion()
    * @since 2.14
    * @generated
@@ -2329,29 +2326,30 @@
   void setEclipsePlatformVersion(GenEclipsePlatformVersion value);
 
   /**
-   * Unsets the value of the '{@link org.eclipse.emf.codegen.ecore.genmodel.GenModel#getEclipsePlatformVersion <em>Eclipse Platform Version</em>}' attribute.
+   * Returns the value of the '<em><b>Model Documentation</b></em>' attribute.
    * <!-- begin-user-doc -->
    * <!-- end-user-doc -->
-   * @see #isSetEclipsePlatformVersion()
-   * @see #getEclipsePlatformVersion()
-   * @see #setEclipsePlatformVersion(GenEclipsePlatformVersion)
+   * <!-- begin-model-doc -->
    * @since 2.14
+   * <!-- end-model-doc -->
+   * @return the value of the '<em>Model Documentation</em>' attribute.
+   * @see #setModelDocumentation(String)
+   * @see org.eclipse.emf.codegen.ecore.genmodel.GenModelPackage#getGenModel_ModelDocumentation()
+   * @model unsettable="true" suppressedIsSetVisibility="true" suppressedUnsetVisibility="true"
    * @generated
    */
-  void unsetEclipsePlatformVersion();
+  String getModelDocumentation();
 
   /**
-   * Returns whether the value of the '{@link org.eclipse.emf.codegen.ecore.genmodel.GenModel#getEclipsePlatformVersion <em>Eclipse Platform Version</em>}' attribute is set.
+   * Sets the value of the '{@link org.eclipse.emf.codegen.ecore.genmodel.GenModel#getModelDocumentation <em>Model Documentation</em>}' attribute.
    * <!-- begin-user-doc -->
    * <!-- end-user-doc -->
-   * @return whether the value of the '<em>Eclipse Platform Version</em>' attribute is set.
-   * @see #unsetEclipsePlatformVersion()
-   * @see #getEclipsePlatformVersion()
-   * @see #setEclipsePlatformVersion(GenEclipsePlatformVersion)
+   * @param value the new value of the '<em>Model Documentation</em>' attribute.
+   * @see #getModelDocumentation()
    * @since 2.14
    * @generated
    */
-  boolean isSetEclipsePlatformVersion();
+  void setModelDocumentation(String value);
 
   EList<GenPackage> getStaticGenPackages();
 
diff --git a/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/GenModelPackage.java b/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/GenModelPackage.java
index e8bc99f..b6aec45 100644
--- a/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/GenModelPackage.java
+++ b/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/GenModelPackage.java
@@ -913,13 +913,23 @@
   int GEN_MODEL__ECLIPSE_PLATFORM_VERSION = GEN_BASE_FEATURE_COUNT + 86;
 
   /**
+   * The feature id for the '<em><b>Model Documentation</b></em>' attribute.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @since 2.14
+   * @generated
+   * @ordered
+   */
+  int GEN_MODEL__MODEL_DOCUMENTATION = GEN_BASE_FEATURE_COUNT + 87;
+
+  /**
    * The number of structural features of the '<em>Gen Model</em>' class.
    * <!-- begin-user-doc -->
    * <!-- end-user-doc -->
    * @generated
    * @ordered
    */
-  int GEN_MODEL_FEATURE_COUNT = GEN_BASE_FEATURE_COUNT + 87;
+  int GEN_MODEL_FEATURE_COUNT = GEN_BASE_FEATURE_COUNT + 88;
 
   /**
    * The meta object id for the '{@link org.eclipse.emf.codegen.ecore.genmodel.impl.GenPackageImpl <em>Gen Package</em>}' class.
@@ -1211,13 +1221,23 @@
   int GEN_PACKAGE__PUBLICATION_LOCATION = GEN_BASE_FEATURE_COUNT + 29;
 
   /**
+   * The feature id for the '<em><b>Documentation</b></em>' attribute.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @since 2.14
+   * @generated
+   * @ordered
+   */
+  int GEN_PACKAGE__DOCUMENTATION = GEN_BASE_FEATURE_COUNT + 30;
+
+  /**
    * The number of structural features of the '<em>Gen Package</em>' class.
    * <!-- begin-user-doc -->
    * <!-- end-user-doc -->
    * @generated
    * @ordered
    */
-  int GEN_PACKAGE_FEATURE_COUNT = GEN_BASE_FEATURE_COUNT + 30;
+  int GEN_PACKAGE_FEATURE_COUNT = GEN_BASE_FEATURE_COUNT + 31;
 
   /**
    * The meta object id for the '{@link org.eclipse.emf.codegen.ecore.genmodel.impl.GenClassifierImpl <em>Gen Classifier</em>}' class.
@@ -1257,13 +1277,23 @@
   int GEN_CLASSIFIER__GEN_TYPE_PARAMETERS = GEN_BASE_FEATURE_COUNT + 1;
 
   /**
+   * The feature id for the '<em><b>Documentation</b></em>' attribute.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @since 2.14
+   * @generated
+   * @ordered
+   */
+  int GEN_CLASSIFIER__DOCUMENTATION = GEN_BASE_FEATURE_COUNT + 2;
+
+  /**
    * The number of structural features of the '<em>Gen Classifier</em>' class.
    * <!-- begin-user-doc -->
    * <!-- end-user-doc -->
    * @generated
    * @ordered
    */
-  int GEN_CLASSIFIER_FEATURE_COUNT = GEN_BASE_FEATURE_COUNT + 2;
+  int GEN_CLASSIFIER_FEATURE_COUNT = GEN_BASE_FEATURE_COUNT + 3;
 
   /**
    * The meta object id for the '{@link org.eclipse.emf.codegen.ecore.genmodel.impl.GenClassImpl <em>Gen Class</em>}' class.
@@ -1303,6 +1333,16 @@
   int GEN_CLASS__GEN_TYPE_PARAMETERS = GEN_CLASSIFIER__GEN_TYPE_PARAMETERS;
 
   /**
+   * The feature id for the '<em><b>Documentation</b></em>' attribute.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @since 2.14
+   * @generated
+   * @ordered
+   */
+  int GEN_CLASS__DOCUMENTATION = GEN_CLASSIFIER__DOCUMENTATION;
+
+  /**
    * The feature id for the '<em><b>Provider</b></em>' attribute.
    * <!-- begin-user-doc -->
    * <!-- end-user-doc -->
@@ -1394,13 +1434,23 @@
   int GEN_TYPED_ELEMENT__GEN_ANNOTATIONS = GEN_BASE__GEN_ANNOTATIONS;
 
   /**
+   * The feature id for the '<em><b>Documentation</b></em>' attribute.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @since 2.14
+   * @generated
+   * @ordered
+   */
+  int GEN_TYPED_ELEMENT__DOCUMENTATION = GEN_BASE_FEATURE_COUNT + 0;
+
+  /**
    * The number of structural features of the '<em>Gen Typed Element</em>' class.
    * <!-- begin-user-doc -->
    * <!-- end-user-doc -->
    * @generated
    * @ordered
    */
-  int GEN_TYPED_ELEMENT_FEATURE_COUNT = GEN_BASE_FEATURE_COUNT + 0;
+  int GEN_TYPED_ELEMENT_FEATURE_COUNT = GEN_BASE_FEATURE_COUNT + 1;
 
   /**
    * The meta object id for the '{@link org.eclipse.emf.codegen.ecore.genmodel.impl.GenFeatureImpl <em>Gen Feature</em>}' class.
@@ -1422,6 +1472,16 @@
   int GEN_FEATURE__GEN_ANNOTATIONS = GEN_TYPED_ELEMENT__GEN_ANNOTATIONS;
 
   /**
+   * The feature id for the '<em><b>Documentation</b></em>' attribute.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @since 2.14
+   * @generated
+   * @ordered
+   */
+  int GEN_FEATURE__DOCUMENTATION = GEN_TYPED_ELEMENT__DOCUMENTATION;
+
+  /**
    * The feature id for the '<em><b>Property</b></em>' attribute.
    * <!-- begin-user-doc -->
    * <!-- end-user-doc -->
@@ -1521,13 +1581,53 @@
   int GEN_FEATURE__ECORE_FEATURE = GEN_TYPED_ELEMENT_FEATURE_COUNT + 10;
 
   /**
+   * The feature id for the '<em><b>Suppressed Get Visibility</b></em>' attribute.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @since 2.14
+   * @generated
+   * @ordered
+   */
+  int GEN_FEATURE__SUPPRESSED_GET_VISIBILITY = GEN_TYPED_ELEMENT_FEATURE_COUNT + 11;
+
+  /**
+   * The feature id for the '<em><b>Suppressed Set Visibility</b></em>' attribute.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @since 2.14
+   * @generated
+   * @ordered
+   */
+  int GEN_FEATURE__SUPPRESSED_SET_VISIBILITY = GEN_TYPED_ELEMENT_FEATURE_COUNT + 12;
+
+  /**
+   * The feature id for the '<em><b>Suppressed Is Set Visibility</b></em>' attribute.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @since 2.14
+   * @generated
+   * @ordered
+   */
+  int GEN_FEATURE__SUPPRESSED_IS_SET_VISIBILITY = GEN_TYPED_ELEMENT_FEATURE_COUNT + 13;
+
+  /**
+   * The feature id for the '<em><b>Suppressed Unset Visibility</b></em>' attribute.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @since 2.14
+   * @generated
+   * @ordered
+   */
+  int GEN_FEATURE__SUPPRESSED_UNSET_VISIBILITY = GEN_TYPED_ELEMENT_FEATURE_COUNT + 14;
+
+  /**
    * The number of structural features of the '<em>Gen Feature</em>' class.
    * <!-- begin-user-doc -->
    * <!-- end-user-doc -->
    * @generated
    * @ordered
    */
-  int GEN_FEATURE_FEATURE_COUNT = GEN_TYPED_ELEMENT_FEATURE_COUNT + 11;
+  int GEN_FEATURE_FEATURE_COUNT = GEN_TYPED_ELEMENT_FEATURE_COUNT + 15;
 
   /**
    * The meta object id for the '{@link org.eclipse.emf.codegen.ecore.genmodel.impl.GenDataTypeImpl <em>Gen Data Type</em>}' class.
@@ -1567,6 +1667,16 @@
   int GEN_DATA_TYPE__GEN_TYPE_PARAMETERS = GEN_CLASSIFIER__GEN_TYPE_PARAMETERS;
 
   /**
+   * The feature id for the '<em><b>Documentation</b></em>' attribute.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @since 2.14
+   * @generated
+   * @ordered
+   */
+  int GEN_DATA_TYPE__DOCUMENTATION = GEN_CLASSIFIER__DOCUMENTATION;
+
+  /**
    * The feature id for the '<em><b>Ecore Data Type</b></em>' reference.
    * <!-- begin-user-doc -->
    * <!-- end-user-doc -->
@@ -1622,6 +1732,16 @@
   int GEN_ENUM__GEN_TYPE_PARAMETERS = GEN_DATA_TYPE__GEN_TYPE_PARAMETERS;
 
   /**
+   * The feature id for the '<em><b>Documentation</b></em>' attribute.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @since 2.14
+   * @generated
+   * @ordered
+   */
+  int GEN_ENUM__DOCUMENTATION = GEN_DATA_TYPE__DOCUMENTATION;
+
+  /**
    * The feature id for the '<em><b>Ecore Data Type</b></em>' reference.
    * <!-- begin-user-doc -->
    * <!-- end-user-doc -->
@@ -1704,13 +1824,23 @@
   int GEN_ENUM_LITERAL__ECORE_ENUM_LITERAL = GEN_BASE_FEATURE_COUNT + 1;
 
   /**
+   * The feature id for the '<em><b>Documentation</b></em>' attribute.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @since 2.14
+   * @generated
+   * @ordered
+   */
+  int GEN_ENUM_LITERAL__DOCUMENTATION = GEN_BASE_FEATURE_COUNT + 2;
+
+  /**
    * The number of structural features of the '<em>Gen Enum Literal</em>' class.
    * <!-- begin-user-doc -->
    * <!-- end-user-doc -->
    * @generated
    * @ordered
    */
-  int GEN_ENUM_LITERAL_FEATURE_COUNT = GEN_BASE_FEATURE_COUNT + 2;
+  int GEN_ENUM_LITERAL_FEATURE_COUNT = GEN_BASE_FEATURE_COUNT + 3;
 
   /**
    * The meta object id for the '{@link org.eclipse.emf.codegen.ecore.genmodel.impl.GenOperationImpl <em>Gen Operation</em>}' class.
@@ -1732,6 +1862,16 @@
   int GEN_OPERATION__GEN_ANNOTATIONS = GEN_TYPED_ELEMENT__GEN_ANNOTATIONS;
 
   /**
+   * The feature id for the '<em><b>Documentation</b></em>' attribute.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @since 2.14
+   * @generated
+   * @ordered
+   */
+  int GEN_OPERATION__DOCUMENTATION = GEN_TYPED_ELEMENT__DOCUMENTATION;
+
+  /**
    * The feature id for the '<em><b>Gen Class</b></em>' container reference.
    * <!-- begin-user-doc -->
    * <!-- end-user-doc -->
@@ -1768,13 +1908,23 @@
   int GEN_OPERATION__GEN_TYPE_PARAMETERS = GEN_TYPED_ELEMENT_FEATURE_COUNT + 3;
 
   /**
+   * The feature id for the '<em><b>Suppressed Visibility</b></em>' attribute.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @since 2.14
+   * @generated
+   * @ordered
+   */
+  int GEN_OPERATION__SUPPRESSED_VISIBILITY = GEN_TYPED_ELEMENT_FEATURE_COUNT + 4;
+
+  /**
    * The number of structural features of the '<em>Gen Operation</em>' class.
    * <!-- begin-user-doc -->
    * <!-- end-user-doc -->
    * @generated
    * @ordered
    */
-  int GEN_OPERATION_FEATURE_COUNT = GEN_TYPED_ELEMENT_FEATURE_COUNT + 4;
+  int GEN_OPERATION_FEATURE_COUNT = GEN_TYPED_ELEMENT_FEATURE_COUNT + 5;
 
   /**
    * The meta object id for the '{@link org.eclipse.emf.codegen.ecore.genmodel.impl.GenParameterImpl <em>Gen Parameter</em>}' class.
@@ -1796,6 +1946,16 @@
   int GEN_PARAMETER__GEN_ANNOTATIONS = GEN_TYPED_ELEMENT__GEN_ANNOTATIONS;
 
   /**
+   * The feature id for the '<em><b>Documentation</b></em>' attribute.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @since 2.14
+   * @generated
+   * @ordered
+   */
+  int GEN_PARAMETER__DOCUMENTATION = GEN_TYPED_ELEMENT__DOCUMENTATION;
+
+  /**
    * The feature id for the '<em><b>Gen Operation</b></em>' container reference.
    * <!-- begin-user-doc -->
    * <!-- end-user-doc -->
@@ -1925,13 +2085,23 @@
   int GEN_TYPE_PARAMETER__ECORE_TYPE_PARAMETER = GEN_BASE_FEATURE_COUNT + 0;
 
   /**
+   * The feature id for the '<em><b>Documentation</b></em>' attribute.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @since 2.14
+   * @generated
+   * @ordered
+   */
+  int GEN_TYPE_PARAMETER__DOCUMENTATION = GEN_BASE_FEATURE_COUNT + 1;
+
+  /**
    * The number of structural features of the '<em>Gen Type Parameter</em>' class.
    * <!-- begin-user-doc -->
    * <!-- end-user-doc -->
    * @generated
    * @ordered
    */
-  int GEN_TYPE_PARAMETER_FEATURE_COUNT = GEN_BASE_FEATURE_COUNT + 1;
+  int GEN_TYPE_PARAMETER_FEATURE_COUNT = GEN_BASE_FEATURE_COUNT + 2;
 
   /**
    * The meta object id for the '{@link org.eclipse.emf.codegen.ecore.genmodel.GenProviderKind <em>Gen Provider Kind</em>}' enum.
@@ -3014,6 +3184,18 @@
   EAttribute getGenModel_EclipsePlatformVersion();
 
   /**
+   * Returns the meta object for the attribute '{@link org.eclipse.emf.codegen.ecore.genmodel.GenModel#getModelDocumentation <em>Model Documentation</em>}'.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @return the meta object for the attribute '<em>Model Documentation</em>'.
+   * @see org.eclipse.emf.codegen.ecore.genmodel.GenModel#getModelDocumentation()
+   * @see #getGenModel()
+   * @since 2.14
+   * @generated
+   */
+  EAttribute getGenModel_ModelDocumentation();
+
+  /**
    * Returns the meta object for class '{@link org.eclipse.emf.codegen.ecore.genmodel.GenPackage <em>Gen Package</em>}'.
    * <!-- begin-user-doc -->
    * <!-- end-user-doc -->
@@ -3354,6 +3536,18 @@
   EAttribute getGenPackage_PublicationLocation();
 
   /**
+   * Returns the meta object for the attribute '{@link org.eclipse.emf.codegen.ecore.genmodel.GenPackage#getDocumentation <em>Documentation</em>}'.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @return the meta object for the attribute '<em>Documentation</em>'.
+   * @see org.eclipse.emf.codegen.ecore.genmodel.GenPackage#getDocumentation()
+   * @see #getGenPackage()
+   * @since 2.14
+   * @generated
+   */
+  EAttribute getGenPackage_Documentation();
+
+  /**
    * Returns the meta object for class '{@link org.eclipse.emf.codegen.ecore.genmodel.GenClass <em>Gen Class</em>}'.
    * <!-- begin-user-doc -->
    * <!-- end-user-doc -->
@@ -3572,6 +3766,54 @@
   EReference getGenFeature_EcoreFeature();
 
   /**
+   * Returns the meta object for the attribute '{@link org.eclipse.emf.codegen.ecore.genmodel.GenFeature#isSuppressedGetVisibility <em>Suppressed Get Visibility</em>}'.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @return the meta object for the attribute '<em>Suppressed Get Visibility</em>'.
+   * @see org.eclipse.emf.codegen.ecore.genmodel.GenFeature#isSuppressedGetVisibility()
+   * @see #getGenFeature()
+   * @since 2.14
+   * @generated
+   */
+  EAttribute getGenFeature_SuppressedGetVisibility();
+
+  /**
+   * Returns the meta object for the attribute '{@link org.eclipse.emf.codegen.ecore.genmodel.GenFeature#isSuppressedSetVisibility <em>Suppressed Set Visibility</em>}'.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @return the meta object for the attribute '<em>Suppressed Set Visibility</em>'.
+   * @see org.eclipse.emf.codegen.ecore.genmodel.GenFeature#isSuppressedSetVisibility()
+   * @see #getGenFeature()
+   * @since 2.14
+   * @generated
+   */
+  EAttribute getGenFeature_SuppressedSetVisibility();
+
+  /**
+   * Returns the meta object for the attribute '{@link org.eclipse.emf.codegen.ecore.genmodel.GenFeature#isSuppressedIsSetVisibility <em>Suppressed Is Set Visibility</em>}'.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @return the meta object for the attribute '<em>Suppressed Is Set Visibility</em>'.
+   * @see org.eclipse.emf.codegen.ecore.genmodel.GenFeature#isSuppressedIsSetVisibility()
+   * @see #getGenFeature()
+   * @since 2.14
+   * @generated
+   */
+  EAttribute getGenFeature_SuppressedIsSetVisibility();
+
+  /**
+   * Returns the meta object for the attribute '{@link org.eclipse.emf.codegen.ecore.genmodel.GenFeature#isSuppressedUnsetVisibility <em>Suppressed Unset Visibility</em>}'.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @return the meta object for the attribute '<em>Suppressed Unset Visibility</em>'.
+   * @see org.eclipse.emf.codegen.ecore.genmodel.GenFeature#isSuppressedUnsetVisibility()
+   * @see #getGenFeature()
+   * @since 2.14
+   * @generated
+   */
+  EAttribute getGenFeature_SuppressedUnsetVisibility();
+
+  /**
    * Returns the meta object for class '{@link org.eclipse.emf.codegen.ecore.genmodel.GenBase <em>Gen Base</em>}'.
    * <!-- begin-user-doc -->
    * <!-- end-user-doc -->
@@ -3668,6 +3910,18 @@
   EReference getGenEnumLiteral_EcoreEnumLiteral();
 
   /**
+   * Returns the meta object for the attribute '{@link org.eclipse.emf.codegen.ecore.genmodel.GenEnumLiteral#getDocumentation <em>Documentation</em>}'.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @return the meta object for the attribute '<em>Documentation</em>'.
+   * @see org.eclipse.emf.codegen.ecore.genmodel.GenEnumLiteral#getDocumentation()
+   * @see #getGenEnumLiteral()
+   * @since 2.14
+   * @generated
+   */
+  EAttribute getGenEnumLiteral_Documentation();
+
+  /**
    * Returns the meta object for class '{@link org.eclipse.emf.codegen.ecore.genmodel.GenClassifier <em>Gen Classifier</em>}'.
    * <!-- begin-user-doc -->
    * <!-- end-user-doc -->
@@ -3700,6 +3954,18 @@
   EReference getGenClassifier_GenTypeParameters();
 
   /**
+   * Returns the meta object for the attribute '{@link org.eclipse.emf.codegen.ecore.genmodel.GenClassifier#getDocumentation <em>Documentation</em>}'.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @return the meta object for the attribute '<em>Documentation</em>'.
+   * @see org.eclipse.emf.codegen.ecore.genmodel.GenClassifier#getDocumentation()
+   * @see #getGenClassifier()
+   * @since 2.14
+   * @generated
+   */
+  EAttribute getGenClassifier_Documentation();
+
+  /**
    * Returns the meta object for class '{@link org.eclipse.emf.codegen.ecore.genmodel.GenDataType <em>Gen Data Type</em>}'.
    * <!-- begin-user-doc -->
    * <!-- end-user-doc -->
@@ -3775,6 +4041,18 @@
   EReference getGenOperation_GenTypeParameters();
 
   /**
+   * Returns the meta object for the attribute '{@link org.eclipse.emf.codegen.ecore.genmodel.GenOperation#isSuppressedVisibility <em>Suppressed Visibility</em>}'.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @return the meta object for the attribute '<em>Suppressed Visibility</em>'.
+   * @see org.eclipse.emf.codegen.ecore.genmodel.GenOperation#isSuppressedVisibility()
+   * @see #getGenOperation()
+   * @since 2.14
+   * @generated
+   */
+  EAttribute getGenOperation_SuppressedVisibility();
+
+  /**
    * Returns the meta object for class '{@link org.eclipse.emf.codegen.ecore.genmodel.GenParameter <em>Gen Parameter</em>}'.
    * <!-- begin-user-doc -->
    * <!-- end-user-doc -->
@@ -3817,6 +4095,18 @@
   EClass getGenTypedElement();
 
   /**
+   * Returns the meta object for the attribute '{@link org.eclipse.emf.codegen.ecore.genmodel.GenTypedElement#getDocumentation <em>Documentation</em>}'.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @return the meta object for the attribute '<em>Documentation</em>'.
+   * @see org.eclipse.emf.codegen.ecore.genmodel.GenTypedElement#getDocumentation()
+   * @see #getGenTypedElement()
+   * @since 2.14
+   * @generated
+   */
+  EAttribute getGenTypedElement_Documentation();
+
+  /**
    * Returns the meta object for class '{@link org.eclipse.emf.codegen.ecore.genmodel.GenAnnotation <em>Gen Annotation</em>}'.
    * <!-- begin-user-doc -->
    * <!-- end-user-doc -->
@@ -3903,6 +4193,18 @@
   EReference getGenTypeParameter_EcoreTypeParameter();
 
   /**
+   * Returns the meta object for the attribute '{@link org.eclipse.emf.codegen.ecore.genmodel.GenTypeParameter#getDocumentation <em>Documentation</em>}'.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @return the meta object for the attribute '<em>Documentation</em>'.
+   * @see org.eclipse.emf.codegen.ecore.genmodel.GenTypeParameter#getDocumentation()
+   * @see #getGenTypeParameter()
+   * @since 2.14
+   * @generated
+   */
+  EAttribute getGenTypeParameter_Documentation();
+
+  /**
    * Returns the meta object for enum '{@link org.eclipse.emf.codegen.ecore.genmodel.GenProviderKind <em>Gen Provider Kind</em>}'.
    * <!-- begin-user-doc -->
    * <!-- end-user-doc -->
@@ -4740,6 +5042,15 @@
     EAttribute GEN_MODEL__ECLIPSE_PLATFORM_VERSION = eINSTANCE.getGenModel_EclipsePlatformVersion();
 
     /**
+     * The meta object literal for the '<em><b>Model Documentation</b></em>' attribute feature.
+     * <!-- begin-user-doc -->
+     * <!-- end-user-doc -->
+     * @since 2.14
+     * @generated
+     */
+    EAttribute GEN_MODEL__MODEL_DOCUMENTATION = eINSTANCE.getGenModel_ModelDocumentation();
+
+    /**
      * The meta object literal for the '{@link org.eclipse.emf.codegen.ecore.genmodel.impl.GenPackageImpl <em>Gen Package</em>}' class.
      * <!-- begin-user-doc -->
      * <!-- end-user-doc -->
@@ -4990,6 +5301,15 @@
     EAttribute GEN_PACKAGE__PUBLICATION_LOCATION = eINSTANCE.getGenPackage_PublicationLocation();
 
     /**
+     * The meta object literal for the '<em><b>Documentation</b></em>' attribute feature.
+     * <!-- begin-user-doc -->
+     * <!-- end-user-doc -->
+     * @since 2.14
+     * @generated
+     */
+    EAttribute GEN_PACKAGE__DOCUMENTATION = eINSTANCE.getGenPackage_Documentation();
+
+    /**
      * The meta object literal for the '{@link org.eclipse.emf.codegen.ecore.genmodel.impl.GenClassImpl <em>Gen Class</em>}' class.
      * <!-- begin-user-doc -->
      * <!-- end-user-doc -->
@@ -5154,6 +5474,42 @@
     EReference GEN_FEATURE__ECORE_FEATURE = eINSTANCE.getGenFeature_EcoreFeature();
 
     /**
+     * The meta object literal for the '<em><b>Suppressed Get Visibility</b></em>' attribute feature.
+     * <!-- begin-user-doc -->
+     * <!-- end-user-doc -->
+     * @since 2.14
+     * @generated
+     */
+    EAttribute GEN_FEATURE__SUPPRESSED_GET_VISIBILITY = eINSTANCE.getGenFeature_SuppressedGetVisibility();
+
+    /**
+     * The meta object literal for the '<em><b>Suppressed Set Visibility</b></em>' attribute feature.
+     * <!-- begin-user-doc -->
+     * <!-- end-user-doc -->
+     * @since 2.14
+     * @generated
+     */
+    EAttribute GEN_FEATURE__SUPPRESSED_SET_VISIBILITY = eINSTANCE.getGenFeature_SuppressedSetVisibility();
+
+    /**
+     * The meta object literal for the '<em><b>Suppressed Is Set Visibility</b></em>' attribute feature.
+     * <!-- begin-user-doc -->
+     * <!-- end-user-doc -->
+     * @since 2.14
+     * @generated
+     */
+    EAttribute GEN_FEATURE__SUPPRESSED_IS_SET_VISIBILITY = eINSTANCE.getGenFeature_SuppressedIsSetVisibility();
+
+    /**
+     * The meta object literal for the '<em><b>Suppressed Unset Visibility</b></em>' attribute feature.
+     * <!-- begin-user-doc -->
+     * <!-- end-user-doc -->
+     * @since 2.14
+     * @generated
+     */
+    EAttribute GEN_FEATURE__SUPPRESSED_UNSET_VISIBILITY = eINSTANCE.getGenFeature_SuppressedUnsetVisibility();
+
+    /**
      * The meta object literal for the '{@link org.eclipse.emf.codegen.ecore.genmodel.impl.GenBaseImpl <em>Gen Base</em>}' class.
      * <!-- begin-user-doc -->
      * <!-- end-user-doc -->
@@ -5232,6 +5588,15 @@
     EReference GEN_ENUM_LITERAL__ECORE_ENUM_LITERAL = eINSTANCE.getGenEnumLiteral_EcoreEnumLiteral();
 
     /**
+     * The meta object literal for the '<em><b>Documentation</b></em>' attribute feature.
+     * <!-- begin-user-doc -->
+     * <!-- end-user-doc -->
+     * @since 2.14
+     * @generated
+     */
+    EAttribute GEN_ENUM_LITERAL__DOCUMENTATION = eINSTANCE.getGenEnumLiteral_Documentation();
+
+    /**
      * The meta object literal for the '{@link org.eclipse.emf.codegen.ecore.genmodel.impl.GenClassifierImpl <em>Gen Classifier</em>}' class.
      * <!-- begin-user-doc -->
      * <!-- end-user-doc -->
@@ -5258,6 +5623,15 @@
     EReference GEN_CLASSIFIER__GEN_TYPE_PARAMETERS = eINSTANCE.getGenClassifier_GenTypeParameters();
 
     /**
+     * The meta object literal for the '<em><b>Documentation</b></em>' attribute feature.
+     * <!-- begin-user-doc -->
+     * <!-- end-user-doc -->
+     * @since 2.14
+     * @generated
+     */
+    EAttribute GEN_CLASSIFIER__DOCUMENTATION = eINSTANCE.getGenClassifier_Documentation();
+
+    /**
      * The meta object literal for the '{@link org.eclipse.emf.codegen.ecore.genmodel.impl.GenDataTypeImpl <em>Gen Data Type</em>}' class.
      * <!-- begin-user-doc -->
      * <!-- end-user-doc -->
@@ -5318,6 +5692,15 @@
     EReference GEN_OPERATION__GEN_TYPE_PARAMETERS = eINSTANCE.getGenOperation_GenTypeParameters();
 
     /**
+     * The meta object literal for the '<em><b>Suppressed Visibility</b></em>' attribute feature.
+     * <!-- begin-user-doc -->
+     * <!-- end-user-doc -->
+     * @since 2.14
+     * @generated
+     */
+    EAttribute GEN_OPERATION__SUPPRESSED_VISIBILITY = eINSTANCE.getGenOperation_SuppressedVisibility();
+
+    /**
      * The meta object literal for the '{@link org.eclipse.emf.codegen.ecore.genmodel.impl.GenParameterImpl <em>Gen Parameter</em>}' class.
      * <!-- begin-user-doc -->
      * <!-- end-user-doc -->
@@ -5354,6 +5737,15 @@
     EClass GEN_TYPED_ELEMENT = eINSTANCE.getGenTypedElement();
 
     /**
+     * The meta object literal for the '<em><b>Documentation</b></em>' attribute feature.
+     * <!-- begin-user-doc -->
+     * <!-- end-user-doc -->
+     * @since 2.14
+     * @generated
+     */
+    EAttribute GEN_TYPED_ELEMENT__DOCUMENTATION = eINSTANCE.getGenTypedElement_Documentation();
+
+    /**
      * The meta object literal for the '{@link org.eclipse.emf.codegen.ecore.genmodel.impl.GenAnnotationImpl <em>Gen Annotation</em>}' class.
      * <!-- begin-user-doc -->
      * <!-- end-user-doc -->
@@ -5422,6 +5814,15 @@
     EReference GEN_TYPE_PARAMETER__ECORE_TYPE_PARAMETER = eINSTANCE.getGenTypeParameter_EcoreTypeParameter();
 
     /**
+     * The meta object literal for the '<em><b>Documentation</b></em>' attribute feature.
+     * <!-- begin-user-doc -->
+     * <!-- end-user-doc -->
+     * @since 2.14
+     * @generated
+     */
+    EAttribute GEN_TYPE_PARAMETER__DOCUMENTATION = eINSTANCE.getGenTypeParameter_Documentation();
+
+    /**
      * The meta object literal for the '{@link org.eclipse.emf.codegen.ecore.genmodel.GenProviderKind <em>Gen Provider Kind</em>}' enum.
      * <!-- begin-user-doc -->
      * <!-- end-user-doc -->
diff --git a/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/GenOperation.java b/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/GenOperation.java
index 0d61ddb..54f9b62 100644
--- a/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/GenOperation.java
+++ b/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/GenOperation.java
@@ -30,6 +30,7 @@
  *   <li>{@link org.eclipse.emf.codegen.ecore.genmodel.GenOperation#getEcoreOperation <em>Ecore Operation</em>}</li>
  *   <li>{@link org.eclipse.emf.codegen.ecore.genmodel.GenOperation#getGenParameters <em>Gen Parameters</em>}</li>
  *   <li>{@link org.eclipse.emf.codegen.ecore.genmodel.GenOperation#getGenTypeParameters <em>Gen Type Parameters</em>}</li>
+ *   <li>{@link org.eclipse.emf.codegen.ecore.genmodel.GenOperation#isSuppressedVisibility <em>Suppressed Visibility</em>}</li>
  * </ul>
  *
  * @see org.eclipse.emf.codegen.ecore.genmodel.GenModelPackage#getGenOperation()
@@ -281,6 +282,17 @@
   boolean isSuppressedVisibility();
 
   /**
+   * Sets the value of the '{@link org.eclipse.emf.codegen.ecore.genmodel.GenOperation#isSuppressedVisibility <em>Suppressed Visibility</em>}' attribute.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @param value the new value of the '<em>Suppressed Visibility</em>' attribute.
+   * @see #isSuppressedVisibility()
+   * @since 2.14
+   * @generated
+   */
+  void setSuppressedVisibility(boolean value);
+
+  /**
    * Returns whether this operation is implemented with a registered invocation delegate.
    * @since 2.6
    */
diff --git a/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/GenPackage.java b/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/GenPackage.java
index d0f42b9..243bbf8 100644
--- a/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/GenPackage.java
+++ b/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/GenPackage.java
@@ -58,6 +58,7 @@
  *   <li>{@link org.eclipse.emf.codegen.ecore.genmodel.GenPackage#getNestedGenPackages <em>Nested Gen Packages</em>}</li>
  *   <li>{@link org.eclipse.emf.codegen.ecore.genmodel.GenPackage#getGenClassifiers <em>Gen Classifiers</em>}</li>
  *   <li>{@link org.eclipse.emf.codegen.ecore.genmodel.GenPackage#getPublicationLocation <em>Publication Location</em>}</li>
+ *   <li>{@link org.eclipse.emf.codegen.ecore.genmodel.GenPackage#getDocumentation <em>Documentation</em>}</li>
  * </ul>
  *
  * @see org.eclipse.emf.codegen.ecore.genmodel.GenModelPackage#getGenPackage()
@@ -719,6 +720,32 @@
    */
   void setPublicationLocation(String value);
 
+  /**
+   * Returns the value of the '<em><b>Documentation</b></em>' attribute.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * <!-- begin-model-doc -->
+   * @since 2.14
+   * <!-- end-model-doc -->
+   * @return the value of the '<em>Documentation</em>' attribute.
+   * @see #setDocumentation(String)
+   * @see org.eclipse.emf.codegen.ecore.genmodel.GenModelPackage#getGenPackage_Documentation()
+   * @model unsettable="true" suppressedIsSetVisibility="true" suppressedUnsetVisibility="true"
+   * @generated
+   */
+  String getDocumentation();
+
+  /**
+   * Sets the value of the '{@link org.eclipse.emf.codegen.ecore.genmodel.GenPackage#getDocumentation <em>Documentation</em>}' attribute.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @param value the new value of the '<em>Documentation</em>' attribute.
+   * @see #getDocumentation()
+   * @since 2.14
+   * @generated
+   */
+  void setDocumentation(String value);
+
   String getInterfacePackageName();
   String getReflectionPackageName();
   String getReflectionClassPackageName();
diff --git a/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/GenTypeParameter.java b/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/GenTypeParameter.java
index 3fc7b88..dc92d97 100644
--- a/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/GenTypeParameter.java
+++ b/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/GenTypeParameter.java
@@ -22,6 +22,7 @@
  * </p>
  * <ul>
  *   <li>{@link org.eclipse.emf.codegen.ecore.genmodel.GenTypeParameter#getEcoreTypeParameter <em>Ecore Type Parameter</em>}</li>
+ *   <li>{@link org.eclipse.emf.codegen.ecore.genmodel.GenTypeParameter#getDocumentation <em>Documentation</em>}</li>
  * </ul>
  *
  * @see org.eclipse.emf.codegen.ecore.genmodel.GenModelPackage#getGenTypeParameter()
@@ -52,6 +53,32 @@
    */
   void setEcoreTypeParameter(ETypeParameter value);
   
+  /**
+   * Returns the value of the '<em><b>Documentation</b></em>' attribute.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * <!-- begin-model-doc -->
+   * @since 2.14
+   * <!-- end-model-doc -->
+   * @return the value of the '<em>Documentation</em>' attribute.
+   * @see #setDocumentation(String)
+   * @see org.eclipse.emf.codegen.ecore.genmodel.GenModelPackage#getGenTypeParameter_Documentation()
+   * @model unsettable="true" suppressedIsSetVisibility="true" suppressedUnsetVisibility="true"
+   * @generated
+   */
+  String getDocumentation();
+
+  /**
+   * Sets the value of the '{@link org.eclipse.emf.codegen.ecore.genmodel.GenTypeParameter#getDocumentation <em>Documentation</em>}' attribute.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @param value the new value of the '<em>Documentation</em>' attribute.
+   * @see #getDocumentation()
+   * @since 2.14
+   * @generated
+   */
+  void setDocumentation(String value);
+
   String getName();
 
   void initialize(ETypeParameter eTypeParameter);
diff --git a/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/GenTypedElement.java b/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/GenTypedElement.java
index 262e9c4..b642a2c 100644
--- a/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/GenTypedElement.java
+++ b/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/GenTypedElement.java
@@ -18,6 +18,12 @@
  * A representation of the model object '<em><b>Gen Typed Element</b></em>'.
  * <!-- end-user-doc -->
  *
+ * <p>
+ * The following features are supported:
+ * </p>
+ * <ul>
+ *   <li>{@link org.eclipse.emf.codegen.ecore.genmodel.GenTypedElement#getDocumentation <em>Documentation</em>}</li>
+ * </ul>
  *
  * @see org.eclipse.emf.codegen.ecore.genmodel.GenModelPackage#getGenTypedElement()
  * @model abstract="true"
@@ -25,6 +31,32 @@
  */
 public interface GenTypedElement extends GenBase
 {
+  /**
+   * Returns the value of the '<em><b>Documentation</b></em>' attribute.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * <!-- begin-model-doc -->
+   * @since 2.14
+   * <!-- end-model-doc -->
+   * @return the value of the '<em>Documentation</em>' attribute.
+   * @see #setDocumentation(String)
+   * @see org.eclipse.emf.codegen.ecore.genmodel.GenModelPackage#getGenTypedElement_Documentation()
+   * @model unsettable="true" suppressedIsSetVisibility="true" suppressedUnsetVisibility="true"
+   * @generated
+   */
+  String getDocumentation();
+
+  /**
+   * Sets the value of the '{@link org.eclipse.emf.codegen.ecore.genmodel.GenTypedElement#getDocumentation <em>Documentation</em>}' attribute.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @param value the new value of the '<em>Documentation</em>' attribute.
+   * @see #getDocumentation()
+   * @since 2.14
+   * @generated
+   */
+  void setDocumentation(String value);
+
   EModelElement getEcoreModelElement();
 
   GenPackage getTypeGenPackage();
diff --git a/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/impl/GenClassImpl.java b/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/impl/GenClassImpl.java
index 9b4efba..18dce47 100644
--- a/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/impl/GenClassImpl.java
+++ b/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/impl/GenClassImpl.java
@@ -2523,7 +2523,7 @@
   public GenFeature getLabelFeature()
   {
     GenFeature labelFeature = getLabelFeatureGen();
-    if (labelFeature != null)
+    if (labelFeature != null || eInternalContainer() == null)
       return labelFeature;
     
     Locale locale = getGenModel().getLocale();
diff --git a/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/impl/GenClassifierImpl.java b/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/impl/GenClassifierImpl.java
index d9b2c28..4644833 100644
--- a/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/impl/GenClassifierImpl.java
+++ b/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/impl/GenClassifierImpl.java
@@ -20,10 +20,12 @@
 import org.eclipse.emf.codegen.ecore.genmodel.GenPackage;
 import org.eclipse.emf.codegen.ecore.genmodel.GenRuntimeVersion;
 import org.eclipse.emf.codegen.ecore.genmodel.GenTypeParameter;
+import org.eclipse.emf.common.notify.Notification;
 import org.eclipse.emf.common.notify.NotificationChain;
 import org.eclipse.emf.common.util.EList;
 import org.eclipse.emf.ecore.EClass;
 import org.eclipse.emf.ecore.InternalEObject;
+import org.eclipse.emf.ecore.impl.ENotificationImpl;
 import org.eclipse.emf.ecore.util.EObjectContainmentEList;
 import org.eclipse.emf.ecore.util.InternalEList;
 import org.eclipse.emf.ecore.EClassifier;
@@ -41,6 +43,7 @@
  * <ul>
  *   <li>{@link org.eclipse.emf.codegen.ecore.genmodel.impl.GenClassifierImpl#getGenPackage <em>Gen Package</em>}</li>
  *   <li>{@link org.eclipse.emf.codegen.ecore.genmodel.impl.GenClassifierImpl#getGenTypeParameters <em>Gen Type Parameters</em>}</li>
+ *   <li>{@link org.eclipse.emf.codegen.ecore.genmodel.impl.GenClassifierImpl#getDocumentation <em>Documentation</em>}</li>
  * </ul>
  *
  * @generated
@@ -58,6 +61,37 @@
   protected EList<GenTypeParameter> genTypeParameters;
 
   /**
+   * The default value of the '{@link #getDocumentation() <em>Documentation</em>}' attribute.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @see #getDocumentation()
+   * @since 2.14
+   * @generated
+   * @ordered
+   */
+  protected static final String DOCUMENTATION_EDEFAULT = null;
+  /**
+   * The cached value of the '{@link #getDocumentation() <em>Documentation</em>}' attribute.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @see #getDocumentation()
+   * @since 2.14
+   * @generated
+   * @ordered
+   */
+  protected String documentation = DOCUMENTATION_EDEFAULT;
+
+  /**
+   * This is true if the Documentation attribute has been set.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @since 2.14
+   * @generated
+   * @ordered
+   */
+  protected boolean documentationESet;
+
+  /**
    * <!-- begin-user-doc -->
    * <!-- end-user-doc -->
    * @generated modifiable
@@ -105,6 +139,66 @@
   /**
    * <!-- begin-user-doc -->
    * <!-- end-user-doc -->
+   * @since 2.14
+   * @generated
+   */
+  public String getDocumentationGen()
+  {
+    return documentation;
+  }
+
+  @Override
+  public String getDocumentation()
+  {
+    return isSetDocumentation() ? getDocumentationGen() : super.getDocumentation();
+  }
+
+  /**
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @since 2.14
+   * @generated
+   */
+  public void setDocumentation(String newDocumentation)
+  {
+    String oldDocumentation = documentation;
+    documentation = newDocumentation;
+    boolean oldDocumentationESet = documentationESet;
+    documentationESet = true;
+    if (eNotificationRequired())
+      eNotify(new ENotificationImpl(this, Notification.SET, GenModelPackage.GEN_CLASSIFIER__DOCUMENTATION, oldDocumentation, documentation, !oldDocumentationESet));
+  }
+
+  /**
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @since 2.14
+   * @generated
+   */
+  public void unsetDocumentation()
+  {
+    String oldDocumentation = documentation;
+    boolean oldDocumentationESet = documentationESet;
+    documentation = DOCUMENTATION_EDEFAULT;
+    documentationESet = false;
+    if (eNotificationRequired())
+      eNotify(new ENotificationImpl(this, Notification.UNSET, GenModelPackage.GEN_CLASSIFIER__DOCUMENTATION, oldDocumentation, DOCUMENTATION_EDEFAULT, oldDocumentationESet));
+  }
+
+  /**
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @since 2.14
+   * @generated
+   */
+  public boolean isSetDocumentation()
+  {
+    return documentationESet;
+  }
+
+  /**
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
    * @generated
    */
   @Override
@@ -132,6 +226,8 @@
         return getGenPackage();
       case GenModelPackage.GEN_CLASSIFIER__GEN_TYPE_PARAMETERS:
         return getGenTypeParameters();
+      case GenModelPackage.GEN_CLASSIFIER__DOCUMENTATION:
+        return getDocumentation();
     }
     return super.eGet(featureID, resolve, coreType);
   }
@@ -151,6 +247,9 @@
         getGenTypeParameters().clear();
         getGenTypeParameters().addAll((Collection<? extends GenTypeParameter>)newValue);
         return;
+      case GenModelPackage.GEN_CLASSIFIER__DOCUMENTATION:
+        setDocumentation((String)newValue);
+        return;
     }
     super.eSet(featureID, newValue);
   }
@@ -168,6 +267,9 @@
       case GenModelPackage.GEN_CLASSIFIER__GEN_TYPE_PARAMETERS:
         getGenTypeParameters().clear();
         return;
+      case GenModelPackage.GEN_CLASSIFIER__DOCUMENTATION:
+        unsetDocumentation();
+        return;
     }
     super.eUnset(featureID);
   }
@@ -186,10 +288,29 @@
         return getGenPackage() != null;
       case GenModelPackage.GEN_CLASSIFIER__GEN_TYPE_PARAMETERS:
         return genTypeParameters != null && !genTypeParameters.isEmpty();
+      case GenModelPackage.GEN_CLASSIFIER__DOCUMENTATION:
+        return isSetDocumentation();
     }
     return super.eIsSet(featureID);
   }
 
+  /**
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @generated
+   */
+  @Override
+  public String toString()
+  {
+    if (eIsProxy()) return super.toString();
+
+    StringBuilder result = new StringBuilder(super.toString());
+    result.append(" (documentation: ");
+    if (documentationESet) result.append(documentation); else result.append("<unset>");
+    result.append(')');
+    return result.toString();
+  }
+
   @Override
   public EModelElement getEcoreModelElement()
   {
diff --git a/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/impl/GenDataTypeImpl.java b/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/impl/GenDataTypeImpl.java
index 2d7b32d..5990787 100644
--- a/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/impl/GenDataTypeImpl.java
+++ b/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/impl/GenDataTypeImpl.java
@@ -878,6 +878,10 @@
   protected void reconcileSettings(GenDataType oldGenDataTypeVersion)
   {
     reconcileGenAnnotations(oldGenDataTypeVersion);
+    if (oldGenDataTypeVersion.eIsSet(GenModelPackage.Literals.GEN_CLASSIFIER__DOCUMENTATION))
+    {
+      setDocumentation(oldGenDataTypeVersion.getDocumentation());
+    }
   }
 
   public boolean reconcile()
diff --git a/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/impl/GenEnumImpl.java b/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/impl/GenEnumImpl.java
index b02e5ea..b9a9639 100644
--- a/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/impl/GenEnumImpl.java
+++ b/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/impl/GenEnumImpl.java
@@ -535,6 +535,10 @@
   {
     setTypeSafeEnumCompatible(oldGenEnumVersion.isTypeSafeEnumCompatible());
     reconcileGenAnnotations(oldGenEnumVersion);
+    if (oldGenEnumVersion.eIsSet(GenModelPackage.Literals.GEN_CLASSIFIER__DOCUMENTATION))
+    {
+      setDocumentation(oldGenEnumVersion.getDocumentation());
+    }
   }
 
   @Override
diff --git a/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/impl/GenEnumLiteralImpl.java b/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/impl/GenEnumLiteralImpl.java
index 91fb07a..9c648c1 100644
--- a/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/impl/GenEnumLiteralImpl.java
+++ b/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/impl/GenEnumLiteralImpl.java
@@ -37,6 +37,7 @@
  * <ul>
  *   <li>{@link org.eclipse.emf.codegen.ecore.genmodel.impl.GenEnumLiteralImpl#getGenEnum <em>Gen Enum</em>}</li>
  *   <li>{@link org.eclipse.emf.codegen.ecore.genmodel.impl.GenEnumLiteralImpl#getEcoreEnumLiteral <em>Ecore Enum Literal</em>}</li>
+ *   <li>{@link org.eclipse.emf.codegen.ecore.genmodel.impl.GenEnumLiteralImpl#getDocumentation <em>Documentation</em>}</li>
  * </ul>
  *
  * @generated
@@ -54,6 +55,37 @@
   protected EEnumLiteral ecoreEnumLiteral;
 
   /**
+   * The default value of the '{@link #getDocumentation() <em>Documentation</em>}' attribute.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @see #getDocumentation()
+   * @since 2.14
+   * @generated
+   * @ordered
+   */
+  protected static final String DOCUMENTATION_EDEFAULT = null;
+  /**
+   * The cached value of the '{@link #getDocumentation() <em>Documentation</em>}' attribute.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @see #getDocumentation()
+   * @since 2.14
+   * @generated
+   * @ordered
+   */
+  protected String documentation = DOCUMENTATION_EDEFAULT;
+
+  /**
+   * This is true if the Documentation attribute has been set.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @since 2.14
+   * @generated
+   * @ordered
+   */
+  protected boolean documentationESet;
+
+  /**
    * <!-- begin-user-doc -->
    * <!-- end-user-doc -->
    * @generated modifiable
@@ -177,6 +209,66 @@
   /**
    * <!-- begin-user-doc -->
    * <!-- end-user-doc -->
+   * @since 2.14
+   * @generated
+   */
+  public String getDocumentationGen()
+  {
+    return documentation;
+  }
+
+  @Override
+  public String getDocumentation()
+  {
+    return isSetDocumentation() ? getDocumentationGen() : super.getDocumentation();
+  }
+
+  /**
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @since 2.14
+   * @generated
+   */
+  public void setDocumentation(String newDocumentation)
+  {
+    String oldDocumentation = documentation;
+    documentation = newDocumentation;
+    boolean oldDocumentationESet = documentationESet;
+    documentationESet = true;
+    if (eNotificationRequired())
+      eNotify(new ENotificationImpl(this, Notification.SET, GenModelPackage.GEN_ENUM_LITERAL__DOCUMENTATION, oldDocumentation, documentation, !oldDocumentationESet));
+  }
+
+  /**
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @since 2.14
+   * @generated
+   */
+  public void unsetDocumentation()
+  {
+    String oldDocumentation = documentation;
+    boolean oldDocumentationESet = documentationESet;
+    documentation = DOCUMENTATION_EDEFAULT;
+    documentationESet = false;
+    if (eNotificationRequired())
+      eNotify(new ENotificationImpl(this, Notification.UNSET, GenModelPackage.GEN_ENUM_LITERAL__DOCUMENTATION, oldDocumentation, DOCUMENTATION_EDEFAULT, oldDocumentationESet));
+  }
+
+  /**
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @since 2.14
+   * @generated
+   */
+  public boolean isSetDocumentation()
+  {
+    return documentationESet;
+  }
+
+  /**
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
    * @generated
    */
   @Override
@@ -239,6 +331,8 @@
       case GenModelPackage.GEN_ENUM_LITERAL__ECORE_ENUM_LITERAL:
         if (resolve) return getEcoreEnumLiteral();
         return basicGetEcoreEnumLiteral();
+      case GenModelPackage.GEN_ENUM_LITERAL__DOCUMENTATION:
+        return getDocumentation();
     }
     return super.eGet(featureID, resolve, coreType);
   }
@@ -259,6 +353,9 @@
       case GenModelPackage.GEN_ENUM_LITERAL__ECORE_ENUM_LITERAL:
         setEcoreEnumLiteral((EEnumLiteral)newValue);
         return;
+      case GenModelPackage.GEN_ENUM_LITERAL__DOCUMENTATION:
+        setDocumentation((String)newValue);
+        return;
     }
     super.eSet(featureID, newValue);
   }
@@ -279,6 +376,9 @@
       case GenModelPackage.GEN_ENUM_LITERAL__ECORE_ENUM_LITERAL:
         setEcoreEnumLiteral((EEnumLiteral)null);
         return;
+      case GenModelPackage.GEN_ENUM_LITERAL__DOCUMENTATION:
+        unsetDocumentation();
+        return;
     }
     super.eUnset(featureID);
   }
@@ -297,10 +397,29 @@
         return getGenEnum() != null;
       case GenModelPackage.GEN_ENUM_LITERAL__ECORE_ENUM_LITERAL:
         return ecoreEnumLiteral != null;
+      case GenModelPackage.GEN_ENUM_LITERAL__DOCUMENTATION:
+        return isSetDocumentation();
     }
     return super.eIsSet(featureID);
   }
 
+  /**
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @generated
+   */
+  @Override
+  public String toString()
+  {
+    if (eIsProxy()) return super.toString();
+
+    StringBuilder result = new StringBuilder(super.toString());
+    result.append(" (documentation: ");
+    if (documentationESet) result.append(documentation); else result.append("<unset>");
+    result.append(')');
+    return result.toString();
+  }
+
   @Override
   public String getName()
   {
@@ -413,6 +532,11 @@
   protected void reconcileSettings(GenEnumLiteral oldGenEnumLiteralVersion)
   {
     reconcileGenAnnotations(oldGenEnumLiteralVersion);
+
+    if (oldGenEnumLiteralVersion.eIsSet(GenModelPackage.Literals.GEN_ENUM_LITERAL__DOCUMENTATION))
+    {
+      setDocumentation(oldGenEnumLiteralVersion.getDocumentation());
+    }
   }
 
   public boolean reconcile()
diff --git a/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/impl/GenFeatureImpl.java b/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/impl/GenFeatureImpl.java
index 16fd187..b5780ac 100644
--- a/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/impl/GenFeatureImpl.java
+++ b/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/impl/GenFeatureImpl.java
@@ -69,6 +69,10 @@
  *   <li>{@link org.eclipse.emf.codegen.ecore.genmodel.impl.GenFeatureImpl#isPropertySortChoices <em>Property Sort Choices</em>}</li>
  *   <li>{@link org.eclipse.emf.codegen.ecore.genmodel.impl.GenFeatureImpl#getGenClass <em>Gen Class</em>}</li>
  *   <li>{@link org.eclipse.emf.codegen.ecore.genmodel.impl.GenFeatureImpl#getEcoreFeature <em>Ecore Feature</em>}</li>
+ *   <li>{@link org.eclipse.emf.codegen.ecore.genmodel.impl.GenFeatureImpl#isSuppressedGetVisibility <em>Suppressed Get Visibility</em>}</li>
+ *   <li>{@link org.eclipse.emf.codegen.ecore.genmodel.impl.GenFeatureImpl#isSuppressedSetVisibility <em>Suppressed Set Visibility</em>}</li>
+ *   <li>{@link org.eclipse.emf.codegen.ecore.genmodel.impl.GenFeatureImpl#isSuppressedIsSetVisibility <em>Suppressed Is Set Visibility</em>}</li>
+ *   <li>{@link org.eclipse.emf.codegen.ecore.genmodel.impl.GenFeatureImpl#isSuppressedUnsetVisibility <em>Suppressed Unset Visibility</em>}</li>
  * </ul>
  *
  * @generated
@@ -265,6 +269,134 @@
   protected EStructuralFeature ecoreFeature;
 
   /**
+   * The default value of the '{@link #isSuppressedGetVisibility() <em>Suppressed Get Visibility</em>}' attribute.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @see #isSuppressedGetVisibility()
+   * @since 2.14
+   * @generated
+   * @ordered
+   */
+  protected static final boolean SUPPRESSED_GET_VISIBILITY_EDEFAULT = false;
+
+  /**
+   * The cached value of the '{@link #isSuppressedGetVisibility() <em>Suppressed Get Visibility</em>}' attribute.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @see #isSuppressedGetVisibility()
+   * @since 2.14
+   * @generated
+   * @ordered
+   */
+  protected boolean suppressedGetVisibility = SUPPRESSED_GET_VISIBILITY_EDEFAULT;
+
+  /**
+   * This is true if the Suppressed Get Visibility attribute has been set.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @since 2.14
+   * @generated
+   * @ordered
+   */
+  protected boolean suppressedGetVisibilityESet;
+
+  /**
+   * The default value of the '{@link #isSuppressedSetVisibility() <em>Suppressed Set Visibility</em>}' attribute.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @see #isSuppressedSetVisibility()
+   * @since 2.14
+   * @generated
+   * @ordered
+   */
+  protected static final boolean SUPPRESSED_SET_VISIBILITY_EDEFAULT = false;
+
+  /**
+   * The cached value of the '{@link #isSuppressedSetVisibility() <em>Suppressed Set Visibility</em>}' attribute.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @see #isSuppressedSetVisibility()
+   * @since 2.14
+   * @generated
+   * @ordered
+   */
+  protected boolean suppressedSetVisibility = SUPPRESSED_SET_VISIBILITY_EDEFAULT;
+
+  /**
+   * This is true if the Suppressed Set Visibility attribute has been set.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @since 2.14
+   * @generated
+   * @ordered
+   */
+  protected boolean suppressedSetVisibilityESet;
+
+  /**
+   * The default value of the '{@link #isSuppressedIsSetVisibility() <em>Suppressed Is Set Visibility</em>}' attribute.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @see #isSuppressedIsSetVisibility()
+   * @since 2.14
+   * @generated
+   * @ordered
+   */
+  protected static final boolean SUPPRESSED_IS_SET_VISIBILITY_EDEFAULT = false;
+
+  /**
+   * The cached value of the '{@link #isSuppressedIsSetVisibility() <em>Suppressed Is Set Visibility</em>}' attribute.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @see #isSuppressedIsSetVisibility()
+   * @since 2.14
+   * @generated
+   * @ordered
+   */
+  protected boolean suppressedIsSetVisibility = SUPPRESSED_IS_SET_VISIBILITY_EDEFAULT;
+
+  /**
+   * This is true if the Suppressed Is Set Visibility attribute has been set.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @since 2.14
+   * @generated
+   * @ordered
+   */
+  protected boolean suppressedIsSetVisibilityESet;
+
+  /**
+   * The default value of the '{@link #isSuppressedUnsetVisibility() <em>Suppressed Unset Visibility</em>}' attribute.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @see #isSuppressedUnsetVisibility()
+   * @since 2.14
+   * @generated
+   * @ordered
+   */
+  protected static final boolean SUPPRESSED_UNSET_VISIBILITY_EDEFAULT = false;
+
+  /**
+   * The cached value of the '{@link #isSuppressedUnsetVisibility() <em>Suppressed Unset Visibility</em>}' attribute.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @see #isSuppressedUnsetVisibility()
+   * @since 2.14
+   * @generated
+   * @ordered
+   */
+  protected boolean suppressedUnsetVisibility = SUPPRESSED_UNSET_VISIBILITY_EDEFAULT;
+
+  /**
+   * This is true if the Suppressed Unset Visibility attribute has been set.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @since 2.14
+   * @generated
+   * @ordered
+   */
+  protected boolean suppressedUnsetVisibilityESet;
+
+  /**
    * <!-- begin-user-doc -->
    * <!-- end-user-doc -->
    * @generated modifiable
@@ -712,6 +844,14 @@
       case GenModelPackage.GEN_FEATURE__ECORE_FEATURE:
         if (resolve) return getEcoreFeature();
         return basicGetEcoreFeature();
+      case GenModelPackage.GEN_FEATURE__SUPPRESSED_GET_VISIBILITY:
+        return isSuppressedGetVisibility();
+      case GenModelPackage.GEN_FEATURE__SUPPRESSED_SET_VISIBILITY:
+        return isSuppressedSetVisibility();
+      case GenModelPackage.GEN_FEATURE__SUPPRESSED_IS_SET_VISIBILITY:
+        return isSuppressedIsSetVisibility();
+      case GenModelPackage.GEN_FEATURE__SUPPRESSED_UNSET_VISIBILITY:
+        return isSuppressedUnsetVisibility();
     }
     return super.eGet(featureID, resolve, coreType);
   }
@@ -761,6 +901,18 @@
       case GenModelPackage.GEN_FEATURE__ECORE_FEATURE:
         setEcoreFeature((EStructuralFeature)newValue);
         return;
+      case GenModelPackage.GEN_FEATURE__SUPPRESSED_GET_VISIBILITY:
+        setSuppressedGetVisibility((Boolean)newValue);
+        return;
+      case GenModelPackage.GEN_FEATURE__SUPPRESSED_SET_VISIBILITY:
+        setSuppressedSetVisibility((Boolean)newValue);
+        return;
+      case GenModelPackage.GEN_FEATURE__SUPPRESSED_IS_SET_VISIBILITY:
+        setSuppressedIsSetVisibility((Boolean)newValue);
+        return;
+      case GenModelPackage.GEN_FEATURE__SUPPRESSED_UNSET_VISIBILITY:
+        setSuppressedUnsetVisibility((Boolean)newValue);
+        return;
     }
     super.eSet(featureID, newValue);
   }
@@ -808,6 +960,18 @@
       case GenModelPackage.GEN_FEATURE__ECORE_FEATURE:
         setEcoreFeature((EStructuralFeature)null);
         return;
+      case GenModelPackage.GEN_FEATURE__SUPPRESSED_GET_VISIBILITY:
+        unsetSuppressedGetVisibility();
+        return;
+      case GenModelPackage.GEN_FEATURE__SUPPRESSED_SET_VISIBILITY:
+        unsetSuppressedSetVisibility();
+        return;
+      case GenModelPackage.GEN_FEATURE__SUPPRESSED_IS_SET_VISIBILITY:
+        unsetSuppressedIsSetVisibility();
+        return;
+      case GenModelPackage.GEN_FEATURE__SUPPRESSED_UNSET_VISIBILITY:
+        unsetSuppressedUnsetVisibility();
+        return;
     }
     super.eUnset(featureID);
   }
@@ -844,6 +1008,14 @@
         return getGenClass() != null;
       case GenModelPackage.GEN_FEATURE__ECORE_FEATURE:
         return ecoreFeature != null;
+      case GenModelPackage.GEN_FEATURE__SUPPRESSED_GET_VISIBILITY:
+        return isSetSuppressedGetVisibility();
+      case GenModelPackage.GEN_FEATURE__SUPPRESSED_SET_VISIBILITY:
+        return isSetSuppressedSetVisibility();
+      case GenModelPackage.GEN_FEATURE__SUPPRESSED_IS_SET_VISIBILITY:
+        return isSetSuppressedIsSetVisibility();
+      case GenModelPackage.GEN_FEATURE__SUPPRESSED_UNSET_VISIBILITY:
+        return isSetSuppressedUnsetVisibility();
     }
     return super.eIsSet(featureID);
   }
@@ -877,6 +1049,14 @@
     result.append(propertyMultiLine);
     result.append(", propertySortChoices: ");
     result.append(propertySortChoices);
+    result.append(", suppressedGetVisibility: ");
+    if (suppressedGetVisibilityESet) result.append(suppressedGetVisibility); else result.append("<unset>");
+    result.append(", suppressedSetVisibility: ");
+    if (suppressedSetVisibilityESet) result.append(suppressedSetVisibility); else result.append("<unset>");
+    result.append(", suppressedIsSetVisibility: ");
+    if (suppressedIsSetVisibilityESet) result.append(suppressedIsSetVisibility); else result.append("<unset>");
+    result.append(", suppressedUnsetVisibility: ");
+    if (suppressedUnsetVisibilityESet) result.append(suppressedUnsetVisibility); else result.append("<unset>");
     result.append(')');
     return result.toString();
   }
@@ -1490,24 +1670,240 @@
     return result;
   }
 
+  /**
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @since 2.14
+   * @generated
+   */
+  public boolean isSuppressedGetVisibilityGen()
+  {
+    return suppressedGetVisibility;
+  }
+
   public boolean isSuppressedGetVisibility()
   {
-    return EcoreUtil.isSuppressedVisibility(getEcoreFeature(), EcoreUtil.GET);
+    return isSetSuppressedGetVisibility() ? isSuppressedGetVisibilityGen() : EcoreUtil.isSuppressedVisibility(getEcoreFeature(), EcoreUtil.GET);
+  }
+
+  /**
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @since 2.14
+   * @generated
+   */
+  public void setSuppressedGetVisibility(boolean newSuppressedGetVisibility)
+  {
+    boolean oldSuppressedGetVisibility = suppressedGetVisibility;
+    suppressedGetVisibility = newSuppressedGetVisibility;
+    boolean oldSuppressedGetVisibilityESet = suppressedGetVisibilityESet;
+    suppressedGetVisibilityESet = true;
+    if (eNotificationRequired())
+      eNotify(new ENotificationImpl(this, Notification.SET, GenModelPackage.GEN_FEATURE__SUPPRESSED_GET_VISIBILITY, oldSuppressedGetVisibility, suppressedGetVisibility, !oldSuppressedGetVisibilityESet));
+  }
+
+  /**
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @since 2.14
+   * @generated
+   */
+  public boolean isSetSuppressedGetVisibility()
+  {
+    return suppressedGetVisibilityESet;
+  }
+
+  /**
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @since 2.14
+   * @generated
+   */
+  public void unsetSuppressedGetVisibility()
+  {
+    boolean oldSuppressedGetVisibility = suppressedGetVisibility;
+    boolean oldSuppressedGetVisibilityESet = suppressedGetVisibilityESet;
+    suppressedGetVisibility = SUPPRESSED_GET_VISIBILITY_EDEFAULT;
+    suppressedGetVisibilityESet = false;
+    if (eNotificationRequired())
+      eNotify(new ENotificationImpl(this, Notification.UNSET, GenModelPackage.GEN_FEATURE__SUPPRESSED_GET_VISIBILITY, oldSuppressedGetVisibility, SUPPRESSED_GET_VISIBILITY_EDEFAULT, oldSuppressedGetVisibilityESet));
+  }
+
+  /**
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @since 2.14
+   * @generated
+   */
+  public boolean isSuppressedSetVisibilityGen()
+  {
+    return suppressedSetVisibility;
   }
 
   public boolean isSuppressedSetVisibility()
   {
-    return EcoreUtil.isSuppressedVisibility(getEcoreFeature(), EcoreUtil.SET);
+    return isSetSuppressedSetVisibility() ?  isSuppressedSetVisibilityGen() : EcoreUtil.isSuppressedVisibility(getEcoreFeature(), EcoreUtil.SET);
+  }
+
+  /**
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @since 2.14
+   * @generated
+   */
+  public void setSuppressedSetVisibility(boolean newSuppressedSetVisibility)
+  {
+    boolean oldSuppressedSetVisibility = suppressedSetVisibility;
+    suppressedSetVisibility = newSuppressedSetVisibility;
+    boolean oldSuppressedSetVisibilityESet = suppressedSetVisibilityESet;
+    suppressedSetVisibilityESet = true;
+    if (eNotificationRequired())
+      eNotify(new ENotificationImpl(this, Notification.SET, GenModelPackage.GEN_FEATURE__SUPPRESSED_SET_VISIBILITY, oldSuppressedSetVisibility, suppressedSetVisibility, !oldSuppressedSetVisibilityESet));
+  }
+
+  /**
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @since 2.14
+   * @generated
+   */
+  public boolean isSetSuppressedSetVisibility()
+  {
+    return suppressedSetVisibilityESet;
+  }
+
+  /**
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @since 2.14
+   * @generated
+   */
+  public void unsetSuppressedSetVisibility()
+  {
+    boolean oldSuppressedSetVisibility = suppressedSetVisibility;
+    boolean oldSuppressedSetVisibilityESet = suppressedSetVisibilityESet;
+    suppressedSetVisibility = SUPPRESSED_SET_VISIBILITY_EDEFAULT;
+    suppressedSetVisibilityESet = false;
+    if (eNotificationRequired())
+      eNotify(new ENotificationImpl(this, Notification.UNSET, GenModelPackage.GEN_FEATURE__SUPPRESSED_SET_VISIBILITY, oldSuppressedSetVisibility, SUPPRESSED_SET_VISIBILITY_EDEFAULT, oldSuppressedSetVisibilityESet));
+  }
+
+  /**
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @since 2.14
+   * @generated
+   */
+  public boolean isSuppressedIsSetVisibilityGen()
+  {
+    return suppressedIsSetVisibility;
   }
 
   public boolean isSuppressedIsSetVisibility()
   {
-    return EcoreUtil.isSuppressedVisibility(getEcoreFeature(), EcoreUtil.IS_SET);
+    return isSetSuppressedIsSetVisibility() ? isSuppressedIsSetVisibilityGen() : EcoreUtil.isSuppressedVisibility(getEcoreFeature(), EcoreUtil.IS_SET);
+  }
+
+  /**
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @since 2.14
+   * @generated
+   */
+  public void setSuppressedIsSetVisibility(boolean newSuppressedIsSetVisibility)
+  {
+    boolean oldSuppressedIsSetVisibility = suppressedIsSetVisibility;
+    suppressedIsSetVisibility = newSuppressedIsSetVisibility;
+    boolean oldSuppressedIsSetVisibilityESet = suppressedIsSetVisibilityESet;
+    suppressedIsSetVisibilityESet = true;
+    if (eNotificationRequired())
+      eNotify(new ENotificationImpl(this, Notification.SET, GenModelPackage.GEN_FEATURE__SUPPRESSED_IS_SET_VISIBILITY, oldSuppressedIsSetVisibility, suppressedIsSetVisibility, !oldSuppressedIsSetVisibilityESet));
+  }
+
+  /**
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @since 2.14
+   * @generated
+   */
+  public boolean isSetSuppressedIsSetVisibility()
+  {
+    return suppressedIsSetVisibilityESet;
+  }
+
+  /**
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @since 2.14
+   * @generated
+   */
+  public void unsetSuppressedIsSetVisibility()
+  {
+    boolean oldSuppressedIsSetVisibility = suppressedIsSetVisibility;
+    boolean oldSuppressedIsSetVisibilityESet = suppressedIsSetVisibilityESet;
+    suppressedIsSetVisibility = SUPPRESSED_IS_SET_VISIBILITY_EDEFAULT;
+    suppressedIsSetVisibilityESet = false;
+    if (eNotificationRequired())
+      eNotify(new ENotificationImpl(this, Notification.UNSET, GenModelPackage.GEN_FEATURE__SUPPRESSED_IS_SET_VISIBILITY, oldSuppressedIsSetVisibility, SUPPRESSED_IS_SET_VISIBILITY_EDEFAULT, oldSuppressedIsSetVisibilityESet));
+  }
+
+  /**
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @since 2.14
+   * @generated
+   */
+  public boolean isSuppressedUnsetVisibilityGen()
+  {
+    return suppressedUnsetVisibility;
   }
 
   public boolean isSuppressedUnsetVisibility()
   {
-    return EcoreUtil.isSuppressedVisibility(getEcoreFeature(), EcoreUtil.UNSET);
+    return isSetSuppressedUnsetVisibility() ? isSuppressedUnsetVisibilityGen() : EcoreUtil.isSuppressedVisibility(getEcoreFeature(), EcoreUtil.UNSET);
+  }
+
+  /**
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @since 2.14
+   * @generated
+   */
+  public void setSuppressedUnsetVisibility(boolean newSuppressedUnsetVisibility)
+  {
+    boolean oldSuppressedUnsetVisibility = suppressedUnsetVisibility;
+    suppressedUnsetVisibility = newSuppressedUnsetVisibility;
+    boolean oldSuppressedUnsetVisibilityESet = suppressedUnsetVisibilityESet;
+    suppressedUnsetVisibilityESet = true;
+    if (eNotificationRequired())
+      eNotify(new ENotificationImpl(this, Notification.SET, GenModelPackage.GEN_FEATURE__SUPPRESSED_UNSET_VISIBILITY, oldSuppressedUnsetVisibility, suppressedUnsetVisibility, !oldSuppressedUnsetVisibilityESet));
+  }
+
+  /**
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @since 2.14
+   * @generated
+   */
+  public boolean isSetSuppressedUnsetVisibility()
+  {
+    return suppressedUnsetVisibilityESet;
+  }
+
+  /**
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @since 2.14
+   * @generated
+   */
+  public void unsetSuppressedUnsetVisibility()
+  {
+    boolean oldSuppressedUnsetVisibility = suppressedUnsetVisibility;
+    boolean oldSuppressedUnsetVisibilityESet = suppressedUnsetVisibilityESet;
+    suppressedUnsetVisibility = SUPPRESSED_UNSET_VISIBILITY_EDEFAULT;
+    suppressedUnsetVisibilityESet = false;
+    if (eNotificationRequired())
+      eNotify(new ENotificationImpl(this, Notification.UNSET, GenModelPackage.GEN_FEATURE__SUPPRESSED_UNSET_VISIBILITY, oldSuppressedUnsetVisibility, SUPPRESSED_UNSET_VISIBILITY_EDEFAULT, oldSuppressedUnsetVisibilityESet));
   }
 
   public void initialize(EStructuralFeature eFeature)
@@ -1820,6 +2216,31 @@
 
     getPropertyFilterFlags().addAll(oldGenFeatureVersion.getPropertyFilterFlags());
     reconcileGenAnnotations(oldGenFeatureVersion);
+
+    if (oldGenFeatureVersion.eIsSet(GenModelPackage.Literals.GEN_TYPED_ELEMENT__DOCUMENTATION))
+    {
+      setDocumentation(oldGenFeatureVersion.getDocumentation());
+    }
+
+    if (oldGenFeatureVersion.eIsSet(GenModelPackage.Literals.GEN_FEATURE__SUPPRESSED_GET_VISIBILITY))
+    {
+      setSuppressedGetVisibility(oldGenFeatureVersion.isSuppressedGetVisibility());
+    }
+
+    if (oldGenFeatureVersion.eIsSet(GenModelPackage.Literals.GEN_FEATURE__SUPPRESSED_SET_VISIBILITY))
+    {
+      setSuppressedSetVisibility(oldGenFeatureVersion.isSuppressedSetVisibility());
+    }
+
+    if (oldGenFeatureVersion.eIsSet(GenModelPackage.Literals.GEN_FEATURE__SUPPRESSED_IS_SET_VISIBILITY))
+    {
+      setSuppressedIsSetVisibility(oldGenFeatureVersion.isSuppressedIsSetVisibility());
+    }
+
+    if (oldGenFeatureVersion.eIsSet(GenModelPackage.Literals.GEN_FEATURE__SUPPRESSED_UNSET_VISIBILITY))
+    {
+      setSuppressedUnsetVisibility(oldGenFeatureVersion.isSuppressedUnsetVisibility());
+    }
   }
 
   public boolean reconcile()
diff --git a/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/impl/GenModelImpl.java b/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/impl/GenModelImpl.java
index 3510f3a..47a6325 100644
--- a/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/impl/GenModelImpl.java
+++ b/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/impl/GenModelImpl.java
@@ -97,7 +97,6 @@
 import org.eclipse.emf.ecore.EObject;
 import org.eclipse.emf.ecore.EOperation;
 import org.eclipse.emf.ecore.EPackage;
-import org.eclipse.emf.ecore.EReference;
 import org.eclipse.emf.ecore.EStructuralFeature;
 import org.eclipse.emf.ecore.ETypeParameter;
 import org.eclipse.emf.ecore.EValidator;
@@ -216,6 +215,7 @@
  *   <li>{@link org.eclipse.emf.codegen.ecore.genmodel.impl.GenModelImpl#isCleanup <em>Cleanup</em>}</li>
  *   <li>{@link org.eclipse.emf.codegen.ecore.genmodel.impl.GenModelImpl#isOSGiCompatible <em>OS Gi Compatible</em>}</li>
  *   <li>{@link org.eclipse.emf.codegen.ecore.genmodel.impl.GenModelImpl#getEclipsePlatformVersion <em>Eclipse Platform Version</em>}</li>
+ *   <li>{@link org.eclipse.emf.codegen.ecore.genmodel.impl.GenModelImpl#getModelDocumentation <em>Model Documentation</em>}</li>
  * </ul>
  *
  * @generated
@@ -1922,6 +1922,38 @@
    */
   protected boolean eclipsePlatformVersionESet;
 
+  /**
+   * The default value of the '{@link #getModelDocumentation() <em>Model Documentation</em>}' attribute.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @see #getModelDocumentation()
+   * @since 2.14
+   * @generated
+   * @ordered
+   */
+  protected static final String MODEL_DOCUMENTATION_EDEFAULT = null;
+
+  /**
+   * The cached value of the '{@link #getModelDocumentation() <em>Model Documentation</em>}' attribute.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @see #getModelDocumentation()
+   * @since 2.14
+   * @generated
+   * @ordered
+   */
+  protected String modelDocumentation = MODEL_DOCUMENTATION_EDEFAULT;
+
+  /**
+   * This is true if the Model Documentation attribute has been set.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @since 2.14
+   * @generated
+   * @ordered
+   */
+  protected boolean modelDocumentationESet;
+
   protected boolean validateModel = false;
 
   /**
@@ -6720,6 +6752,81 @@
   /**
    * <!-- begin-user-doc -->
    * <!-- end-user-doc -->
+   * @since 2.14
+   * @generated
+   */
+  public String getModelDocumentationGen()
+  {
+    return modelDocumentation;
+  }
+
+  public String getModelDocumentation()
+  {
+    if (isSetModelDocumentation())
+    {
+      return getModelDocumentationGen();
+    }
+    else
+    {
+      GenPackage mainGenPackage = getMainGenPackage();
+      if (mainGenPackage != null)
+      {
+        EPackage mainEPackage = mainGenPackage.getEcorePackage();
+        if (mainEPackage != null)
+        {
+          return EcoreUtil.getAnnotation(mainEPackage, GenModelPackage.eNS_URI, "modelDocumentation");
+        }
+      }
+      return null;
+    }
+  }
+
+  /**
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @since 2.14
+   * @generated
+   */
+  public void setModelDocumentation(String newModelDocumentation)
+  {
+    String oldModelDocumentation = modelDocumentation;
+    modelDocumentation = newModelDocumentation;
+    boolean oldModelDocumentationESet = modelDocumentationESet;
+    modelDocumentationESet = true;
+    if (eNotificationRequired())
+      eNotify(new ENotificationImpl(this, Notification.SET, GenModelPackage.GEN_MODEL__MODEL_DOCUMENTATION, oldModelDocumentation, modelDocumentation, !oldModelDocumentationESet));
+  }
+
+  /**
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @since 2.14
+   * @generated
+   */
+  public void unsetModelDocumentation()
+  {
+    String oldModelDocumentation = modelDocumentation;
+    boolean oldModelDocumentationESet = modelDocumentationESet;
+    modelDocumentation = MODEL_DOCUMENTATION_EDEFAULT;
+    modelDocumentationESet = false;
+    if (eNotificationRequired())
+      eNotify(new ENotificationImpl(this, Notification.UNSET, GenModelPackage.GEN_MODEL__MODEL_DOCUMENTATION, oldModelDocumentation, MODEL_DOCUMENTATION_EDEFAULT, oldModelDocumentationESet));
+  }
+
+  /**
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @since 2.14
+   * @generated
+   */
+  public boolean isSetModelDocumentation()
+  {
+    return modelDocumentationESet;
+  }
+
+  /**
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
    * @generated
    */
   @SuppressWarnings("unchecked")
@@ -6934,6 +7041,8 @@
         return isOSGiCompatible();
       case GenModelPackage.GEN_MODEL__ECLIPSE_PLATFORM_VERSION:
         return getEclipsePlatformVersion();
+      case GenModelPackage.GEN_MODEL__MODEL_DOCUMENTATION:
+        return getModelDocumentation();
     }
     return super.eGet(featureID, resolve, coreType);
   }
@@ -7219,6 +7328,9 @@
       case GenModelPackage.GEN_MODEL__ECLIPSE_PLATFORM_VERSION:
         setEclipsePlatformVersion((GenEclipsePlatformVersion)newValue);
         return;
+      case GenModelPackage.GEN_MODEL__MODEL_DOCUMENTATION:
+        setModelDocumentation((String)newValue);
+        return;
     }
     super.eSet(featureID, newValue);
   }
@@ -7494,6 +7606,9 @@
       case GenModelPackage.GEN_MODEL__ECLIPSE_PLATFORM_VERSION:
         unsetEclipsePlatformVersion();
         return;
+      case GenModelPackage.GEN_MODEL__MODEL_DOCUMENTATION:
+        unsetModelDocumentation();
+        return;
     }
     super.eUnset(featureID);
   }
@@ -7682,6 +7797,8 @@
         return oSGiCompatible != OS_GI_COMPATIBLE_EDEFAULT;
       case GenModelPackage.GEN_MODEL__ECLIPSE_PLATFORM_VERSION:
         return isSetEclipsePlatformVersion();
+      case GenModelPackage.GEN_MODEL__MODEL_DOCUMENTATION:
+        return isSetModelDocumentation();
     }
     return super.eIsSet(featureID);
   }
@@ -7861,6 +7978,8 @@
     result.append(oSGiCompatible);
     result.append(", eclipsePlatformVersion: ");
     if (eclipsePlatformVersionESet) result.append(eclipsePlatformVersion); else result.append("<unset>");
+    result.append(", modelDocumentation: ");
+    if (modelDocumentationESet) result.append(modelDocumentation); else result.append("<unset>");
     result.append(')');
     return result.toString();
   }
@@ -9190,6 +9309,16 @@
     setStyleProviders(oldGenModelVersion.isStyleProviders());
     
     setOSGiCompatible(oldGenModelVersion.isOSGiCompatible());
+
+    if (oldGenModelVersion.eIsSet(GenModelPackage.Literals.GEN_MODEL__ECLIPSE_PLATFORM_VERSION))
+    {
+      setEclipsePlatformVersion(oldGenModelVersion.getEclipsePlatformVersion());
+    }
+
+    if (oldGenModelVersion.eIsSet(GenModelPackage.Literals.GEN_MODEL__MODEL_DOCUMENTATION))
+    {
+      setModelDocumentation(oldGenModelVersion.getModelDocumentation());
+    }
   }
 
   private boolean isReconciling;
@@ -9238,6 +9367,8 @@
           }
         }
 
+        handleAnnotations(null);
+
         return !genPackages.isEmpty();
       }
       finally
@@ -10104,6 +10235,20 @@
 
     if (handleAnnotations)
     {
+      handleAnnotations(result);
+    }
+
+    return result;
+  }
+
+  /**
+   * @since 2.14
+   */
+  protected void handleAnnotations(Collection<Runnable> runnables)
+  {
+    GenPackage mainGenPackage = getMainGenPackage();
+    if (mainGenPackage != null)
+    {
       handleAnnotations(this, mainGenPackage.getEcorePackage());
       for (TreeIterator<EObject> i = eAllContents(); i.hasNext();)
       {
@@ -10114,20 +10259,18 @@
           EModelElement eModelElement = genBase.getEcoreModelElement();
           if (eModelElement != null)
           {
-            if (result == null)
+            if (runnables == null)
             {
               handleAnnotations(genBase, eModelElement);
             }
             else
             {
-              handleAnnotations(result, genBase, eModelElement);
+              handleAnnotations(runnables, genBase, eModelElement);
             }
           }
         }
       }
     }
-
-    return result;
   }
 
   /**
@@ -10177,19 +10320,51 @@
           }
           if (value != null)
           {
-            genBase.eSet(eStructuralFeature, value);
+            // Only set the value for features that are not implemented to directly derive their value from the annotation.
+            boolean isFeatureDerivedDirectlyFromAnnotation =
+              eStructuralFeature == GenModelPackage.Literals.GEN_MODEL__MODEL_DOCUMENTATION ||
+                eStructuralFeature == GenModelPackage.Literals.GEN_PACKAGE__DOCUMENTATION ||
+                eStructuralFeature == GenModelPackage.Literals.GEN_FEATURE__SUPPRESSED_GET_VISIBILITY ||
+                eStructuralFeature == GenModelPackage.Literals.GEN_FEATURE__SUPPRESSED_SET_VISIBILITY ||
+                eStructuralFeature == GenModelPackage.Literals.GEN_FEATURE__SUPPRESSED_IS_SET_VISIBILITY ||
+                eStructuralFeature == GenModelPackage.Literals.GEN_FEATURE__SUPPRESSED_UNSET_VISIBILITY ||
+                eStructuralFeature == GenModelPackage.Literals.GEN_ENUM_LITERAL__DOCUMENTATION ||
+                eStructuralFeature == GenModelPackage.Literals.GEN_CLASSIFIER__DOCUMENTATION ||
+                eStructuralFeature == GenModelPackage.Literals.GEN_OPERATION__SUPPRESSED_VISIBILITY ||
+                eStructuralFeature == GenModelPackage.Literals.GEN_TYPED_ELEMENT__DOCUMENTATION ||
+                eStructuralFeature == GenModelPackage.Literals.GEN_TYPE_PARAMETER__DOCUMENTATION;
+            if (!isFeatureDerivedDirectlyFromAnnotation)
+            {
+              genBase.eSet(eStructuralFeature, value);
+            }
           }
         }
-        else if (eStructuralFeature instanceof EReference && genBase instanceof GenClass)
+        else if (eStructuralFeature == GenModelPackage.Literals.GEN_CLASS__LABEL_FEATURE && literal != null)
         {
           if (runnables == null)
           {
-            for (GenFeature genFeature : ((GenClass)genBase).getAllGenFeatures())
+            GenClass genClass = (GenClass)genBase;
+            if (genClass.eContainer() == null)
             {
-              if (literal.equals(genFeature.getName()))
+              for (EStructuralFeature feature : ((EClass)eModelElement).getEAllStructuralFeatures())
               {
-                genBase.eSet(eStructuralFeature, genFeature);
-                break;
+                if (literal.equals(feature.getName()))
+                {
+                  GenFeature genFeature = GenModelFactory.eINSTANCE.createGenFeature();
+                  genFeature.setEcoreFeature(feature);
+                  genClass.setLabelFeature(genFeature);
+                }
+              }
+            }
+            else
+            {
+              for (GenFeature genFeature : genClass.getAllGenFeatures())
+              {
+                if (literal.equals(genFeature.getName()))
+                {
+                  genClass.setLabelFeature(genFeature);
+                  break;
+                }
               }
             }
           }
@@ -10427,7 +10602,7 @@
   @Override
   protected String getDocumentation()
   {
-    return GenModelUtil.getAnnotation(this, GenModelPackage.eNS_URI, "documentation");
+    return getModelDocumentation();
   }
 
 } //GenModelImpl
diff --git a/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/impl/GenModelPackageImpl.java b/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/impl/GenModelPackageImpl.java
index 0b63f59..0e0df73 100644
--- a/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/impl/GenModelPackageImpl.java
+++ b/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/impl/GenModelPackageImpl.java
@@ -1190,6 +1190,17 @@
   /**
    * <!-- begin-user-doc -->
    * <!-- end-user-doc -->
+   * @since 2.14
+   * @generated
+   */
+  public EAttribute getGenModel_ModelDocumentation()
+  {
+    return (EAttribute)genModelEClass.getEStructuralFeatures().get(87);
+  }
+
+  /**
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
    * @generated
    */
   public EClass getGenPackage()
@@ -1500,6 +1511,17 @@
   /**
    * <!-- begin-user-doc -->
    * <!-- end-user-doc -->
+   * @since 2.14
+   * @generated
+   */
+  public EAttribute getGenPackage_Documentation()
+  {
+    return (EAttribute)genPackageEClass.getEStructuralFeatures().get(30);
+  }
+
+  /**
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
    * @generated
    */
   public EClass getGenClass()
@@ -1700,6 +1722,50 @@
   /**
    * <!-- begin-user-doc -->
    * <!-- end-user-doc -->
+   * @since 2.14
+   * @generated
+   */
+  public EAttribute getGenFeature_SuppressedGetVisibility()
+  {
+    return (EAttribute)genFeatureEClass.getEStructuralFeatures().get(11);
+  }
+
+  /**
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @since 2.14
+   * @generated
+   */
+  public EAttribute getGenFeature_SuppressedSetVisibility()
+  {
+    return (EAttribute)genFeatureEClass.getEStructuralFeatures().get(12);
+  }
+
+  /**
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @since 2.14
+   * @generated
+   */
+  public EAttribute getGenFeature_SuppressedIsSetVisibility()
+  {
+    return (EAttribute)genFeatureEClass.getEStructuralFeatures().get(13);
+  }
+
+  /**
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @since 2.14
+   * @generated
+   */
+  public EAttribute getGenFeature_SuppressedUnsetVisibility()
+  {
+    return (EAttribute)genFeatureEClass.getEStructuralFeatures().get(14);
+  }
+
+  /**
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
    * @generated
    */
   public EClass getGenBase()
@@ -1790,6 +1856,17 @@
   /**
    * <!-- begin-user-doc -->
    * <!-- end-user-doc -->
+   * @since 2.14
+   * @generated
+   */
+  public EAttribute getGenEnumLiteral_Documentation()
+  {
+    return (EAttribute)genEnumLiteralEClass.getEStructuralFeatures().get(2);
+  }
+
+  /**
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
    * @generated
    */
   public EClass getGenClassifier()
@@ -1820,6 +1897,17 @@
   /**
    * <!-- begin-user-doc -->
    * <!-- end-user-doc -->
+   * @since 2.14
+   * @generated
+   */
+  public EAttribute getGenClassifier_Documentation()
+  {
+    return (EAttribute)genClassifierEClass.getEStructuralFeatures().get(2);
+  }
+
+  /**
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
    * @generated
    */
   public EClass getGenDataType()
@@ -1890,6 +1978,17 @@
   /**
    * <!-- begin-user-doc -->
    * <!-- end-user-doc -->
+   * @since 2.14
+   * @generated
+   */
+  public EAttribute getGenOperation_SuppressedVisibility()
+  {
+    return (EAttribute)genOperationEClass.getEStructuralFeatures().get(4);
+  }
+
+  /**
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
    * @generated
    */
   public EClass getGenParameter()
@@ -1930,6 +2029,17 @@
   /**
    * <!-- begin-user-doc -->
    * <!-- end-user-doc -->
+   * @since 2.14
+   * @generated
+   */
+  public EAttribute getGenTypedElement_Documentation()
+  {
+    return (EAttribute)genTypedElementEClass.getEStructuralFeatures().get(0);
+  }
+
+  /**
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
    * @generated
    */
   public EClass getGenAnnotation()
@@ -2010,6 +2120,17 @@
   /**
    * <!-- begin-user-doc -->
    * <!-- end-user-doc -->
+   * @since 2.14
+   * @generated
+   */
+  public EAttribute getGenTypeParameter_Documentation()
+  {
+    return (EAttribute)genTypeParameterEClass.getEStructuralFeatures().get(1);
+  }
+
+  /**
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
    * @generated
    */
   public EEnum getGenProviderKind()
@@ -2227,6 +2348,7 @@
     createEAttribute(genModelEClass, GEN_MODEL__CLEANUP);
     createEAttribute(genModelEClass, GEN_MODEL__OS_GI_COMPATIBLE);
     createEAttribute(genModelEClass, GEN_MODEL__ECLIPSE_PLATFORM_VERSION);
+    createEAttribute(genModelEClass, GEN_MODEL__MODEL_DOCUMENTATION);
 
     genPackageEClass = createEClass(GEN_PACKAGE);
     createEAttribute(genPackageEClass, GEN_PACKAGE__PREFIX);
@@ -2259,6 +2381,7 @@
     createEReference(genPackageEClass, GEN_PACKAGE__NESTED_GEN_PACKAGES);
     createEReference(genPackageEClass, GEN_PACKAGE__GEN_CLASSIFIERS);
     createEAttribute(genPackageEClass, GEN_PACKAGE__PUBLICATION_LOCATION);
+    createEAttribute(genPackageEClass, GEN_PACKAGE__DOCUMENTATION);
 
     genClassEClass = createEClass(GEN_CLASS);
     createEAttribute(genClassEClass, GEN_CLASS__PROVIDER);
@@ -2281,6 +2404,10 @@
     createEAttribute(genFeatureEClass, GEN_FEATURE__PROPERTY_SORT_CHOICES);
     createEReference(genFeatureEClass, GEN_FEATURE__GEN_CLASS);
     createEReference(genFeatureEClass, GEN_FEATURE__ECORE_FEATURE);
+    createEAttribute(genFeatureEClass, GEN_FEATURE__SUPPRESSED_GET_VISIBILITY);
+    createEAttribute(genFeatureEClass, GEN_FEATURE__SUPPRESSED_SET_VISIBILITY);
+    createEAttribute(genFeatureEClass, GEN_FEATURE__SUPPRESSED_IS_SET_VISIBILITY);
+    createEAttribute(genFeatureEClass, GEN_FEATURE__SUPPRESSED_UNSET_VISIBILITY);
 
     genBaseEClass = createEClass(GEN_BASE);
     createEReference(genBaseEClass, GEN_BASE__GEN_ANNOTATIONS);
@@ -2293,10 +2420,12 @@
     genEnumLiteralEClass = createEClass(GEN_ENUM_LITERAL);
     createEReference(genEnumLiteralEClass, GEN_ENUM_LITERAL__GEN_ENUM);
     createEReference(genEnumLiteralEClass, GEN_ENUM_LITERAL__ECORE_ENUM_LITERAL);
+    createEAttribute(genEnumLiteralEClass, GEN_ENUM_LITERAL__DOCUMENTATION);
 
     genClassifierEClass = createEClass(GEN_CLASSIFIER);
     createEReference(genClassifierEClass, GEN_CLASSIFIER__GEN_PACKAGE);
     createEReference(genClassifierEClass, GEN_CLASSIFIER__GEN_TYPE_PARAMETERS);
+    createEAttribute(genClassifierEClass, GEN_CLASSIFIER__DOCUMENTATION);
 
     genDataTypeEClass = createEClass(GEN_DATA_TYPE);
     createEReference(genDataTypeEClass, GEN_DATA_TYPE__ECORE_DATA_TYPE);
@@ -2306,12 +2435,14 @@
     createEReference(genOperationEClass, GEN_OPERATION__ECORE_OPERATION);
     createEReference(genOperationEClass, GEN_OPERATION__GEN_PARAMETERS);
     createEReference(genOperationEClass, GEN_OPERATION__GEN_TYPE_PARAMETERS);
+    createEAttribute(genOperationEClass, GEN_OPERATION__SUPPRESSED_VISIBILITY);
 
     genParameterEClass = createEClass(GEN_PARAMETER);
     createEReference(genParameterEClass, GEN_PARAMETER__GEN_OPERATION);
     createEReference(genParameterEClass, GEN_PARAMETER__ECORE_PARAMETER);
 
     genTypedElementEClass = createEClass(GEN_TYPED_ELEMENT);
+    createEAttribute(genTypedElementEClass, GEN_TYPED_ELEMENT__DOCUMENTATION);
 
     genAnnotationEClass = createEClass(GEN_ANNOTATION);
     createEAttribute(genAnnotationEClass, GEN_ANNOTATION__SOURCE);
@@ -2322,6 +2453,7 @@
 
     genTypeParameterEClass = createEClass(GEN_TYPE_PARAMETER);
     createEReference(genTypeParameterEClass, GEN_TYPE_PARAMETER__ECORE_TYPE_PARAMETER);
+    createEAttribute(genTypeParameterEClass, GEN_TYPE_PARAMETER__DOCUMENTATION);
 
     // Create enums
     genProviderKindEEnum = createEEnum(GEN_PROVIDER_KIND);
@@ -2473,6 +2605,7 @@
     initEAttribute(getGenModel_Cleanup(), ecorePackage.getEBoolean(), "cleanup", null, 0, 1, GenModel.class, !IS_TRANSIENT, !IS_VOLATILE, IS_CHANGEABLE, !IS_UNSETTABLE, !IS_ID, IS_UNIQUE, !IS_DERIVED, IS_ORDERED);
     initEAttribute(getGenModel_OSGiCompatible(), theEcorePackage.getEBoolean(), "oSGiCompatible", null, 0, 1, GenModel.class, !IS_TRANSIENT, !IS_VOLATILE, IS_CHANGEABLE, !IS_UNSETTABLE, !IS_ID, IS_UNIQUE, !IS_DERIVED, IS_ORDERED);
     initEAttribute(getGenModel_EclipsePlatformVersion(), this.getGenEclipsePlatformVersion(), "eclipsePlatformVersion", null, 0, 1, GenModel.class, !IS_TRANSIENT, !IS_VOLATILE, IS_CHANGEABLE, IS_UNSETTABLE, !IS_ID, IS_UNIQUE, !IS_DERIVED, IS_ORDERED);
+    initEAttribute(getGenModel_ModelDocumentation(), theEcorePackage.getEString(), "modelDocumentation", null, 0, 1, GenModel.class, !IS_TRANSIENT, !IS_VOLATILE, IS_CHANGEABLE, IS_UNSETTABLE, !IS_ID, IS_UNIQUE, !IS_DERIVED, IS_ORDERED);
 
     initEClass(genPackageEClass, GenPackage.class, "GenPackage", !IS_ABSTRACT, !IS_INTERFACE, IS_GENERATED_INSTANCE_CLASS);
     initEAttribute(getGenPackage_Prefix(), ecorePackage.getEString(), "prefix", null, 0, 1, GenPackage.class, !IS_TRANSIENT, !IS_VOLATILE, IS_CHANGEABLE, !IS_UNSETTABLE, !IS_ID, IS_UNIQUE, !IS_DERIVED, IS_ORDERED);
@@ -2505,6 +2638,7 @@
     initEReference(getGenPackage_NestedGenPackages(), this.getGenPackage(), null, "nestedGenPackages", null, 0, -1, GenPackage.class, !IS_TRANSIENT, !IS_VOLATILE, IS_CHANGEABLE, IS_COMPOSITE, !IS_RESOLVE_PROXIES, !IS_UNSETTABLE, IS_UNIQUE, !IS_DERIVED, IS_ORDERED);
     initEReference(getGenPackage_GenClassifiers(), this.getGenClassifier(), this.getGenClassifier_GenPackage(), "genClassifiers", null, 0, -1, GenPackage.class, IS_TRANSIENT, IS_VOLATILE, !IS_CHANGEABLE, !IS_COMPOSITE, !IS_RESOLVE_PROXIES, !IS_UNSETTABLE, IS_UNIQUE, !IS_DERIVED, IS_ORDERED);
     initEAttribute(getGenPackage_PublicationLocation(), theEcorePackage.getEString(), "publicationLocation", null, 0, 1, GenPackage.class, !IS_TRANSIENT, !IS_VOLATILE, IS_CHANGEABLE, !IS_UNSETTABLE, !IS_ID, IS_UNIQUE, !IS_DERIVED, IS_ORDERED);
+    initEAttribute(getGenPackage_Documentation(), theEcorePackage.getEString(), "documentation", null, 0, 1, GenPackage.class, !IS_TRANSIENT, !IS_VOLATILE, IS_CHANGEABLE, IS_UNSETTABLE, !IS_ID, IS_UNIQUE, !IS_DERIVED, IS_ORDERED);
 
     initEClass(genClassEClass, GenClass.class, "GenClass", !IS_ABSTRACT, !IS_INTERFACE, IS_GENERATED_INSTANCE_CLASS);
     initEAttribute(getGenClass_Provider(), this.getGenProviderKind(), "provider", null, 0, 1, GenClass.class, !IS_TRANSIENT, !IS_VOLATILE, IS_CHANGEABLE, !IS_UNSETTABLE, !IS_ID, IS_UNIQUE, !IS_DERIVED, IS_ORDERED);
@@ -2527,6 +2661,10 @@
     initEAttribute(getGenFeature_PropertySortChoices(), ecorePackage.getEBoolean(), "propertySortChoices", null, 0, 1, GenFeature.class, !IS_TRANSIENT, !IS_VOLATILE, IS_CHANGEABLE, !IS_UNSETTABLE, !IS_ID, IS_UNIQUE, !IS_DERIVED, IS_ORDERED);
     initEReference(getGenFeature_GenClass(), this.getGenClass(), this.getGenClass_GenFeatures(), "genClass", null, 1, 1, GenFeature.class, IS_TRANSIENT, !IS_VOLATILE, IS_CHANGEABLE, !IS_COMPOSITE, !IS_RESOLVE_PROXIES, !IS_UNSETTABLE, IS_UNIQUE, !IS_DERIVED, IS_ORDERED);
     initEReference(getGenFeature_EcoreFeature(), theEcorePackage.getEStructuralFeature(), null, "ecoreFeature", null, 1, 1, GenFeature.class, !IS_TRANSIENT, !IS_VOLATILE, IS_CHANGEABLE, !IS_COMPOSITE, IS_RESOLVE_PROXIES, !IS_UNSETTABLE, IS_UNIQUE, !IS_DERIVED, IS_ORDERED);
+    initEAttribute(getGenFeature_SuppressedGetVisibility(), theEcorePackage.getEBoolean(), "suppressedGetVisibility", null, 0, 1, GenFeature.class, !IS_TRANSIENT, !IS_VOLATILE, IS_CHANGEABLE, IS_UNSETTABLE, !IS_ID, IS_UNIQUE, !IS_DERIVED, IS_ORDERED);
+    initEAttribute(getGenFeature_SuppressedSetVisibility(), theEcorePackage.getEBoolean(), "suppressedSetVisibility", null, 0, 1, GenFeature.class, !IS_TRANSIENT, !IS_VOLATILE, IS_CHANGEABLE, IS_UNSETTABLE, !IS_ID, IS_UNIQUE, !IS_DERIVED, IS_ORDERED);
+    initEAttribute(getGenFeature_SuppressedIsSetVisibility(), theEcorePackage.getEBoolean(), "suppressedIsSetVisibility", null, 0, 1, GenFeature.class, !IS_TRANSIENT, !IS_VOLATILE, IS_CHANGEABLE, IS_UNSETTABLE, !IS_ID, IS_UNIQUE, !IS_DERIVED, IS_ORDERED);
+    initEAttribute(getGenFeature_SuppressedUnsetVisibility(), theEcorePackage.getEBoolean(), "suppressedUnsetVisibility", null, 0, 1, GenFeature.class, !IS_TRANSIENT, !IS_VOLATILE, IS_CHANGEABLE, IS_UNSETTABLE, !IS_ID, IS_UNIQUE, !IS_DERIVED, IS_ORDERED);
 
     initEClass(genBaseEClass, GenBase.class, "GenBase", IS_ABSTRACT, !IS_INTERFACE, IS_GENERATED_INSTANCE_CLASS);
     initEReference(getGenBase_GenAnnotations(), this.getGenAnnotation(), this.getGenAnnotation_GenBase(), "genAnnotations", null, 0, -1, GenBase.class, !IS_TRANSIENT, !IS_VOLATILE, IS_CHANGEABLE, IS_COMPOSITE, !IS_RESOLVE_PROXIES, !IS_UNSETTABLE, IS_UNIQUE, !IS_DERIVED, IS_ORDERED);
@@ -2542,10 +2680,12 @@
     initEClass(genEnumLiteralEClass, GenEnumLiteral.class, "GenEnumLiteral", !IS_ABSTRACT, !IS_INTERFACE, IS_GENERATED_INSTANCE_CLASS);
     initEReference(getGenEnumLiteral_GenEnum(), this.getGenEnum(), this.getGenEnum_GenEnumLiterals(), "genEnum", null, 1, 1, GenEnumLiteral.class, IS_TRANSIENT, !IS_VOLATILE, IS_CHANGEABLE, !IS_COMPOSITE, !IS_RESOLVE_PROXIES, !IS_UNSETTABLE, IS_UNIQUE, !IS_DERIVED, IS_ORDERED);
     initEReference(getGenEnumLiteral_EcoreEnumLiteral(), theEcorePackage.getEEnumLiteral(), null, "ecoreEnumLiteral", null, 1, 1, GenEnumLiteral.class, !IS_TRANSIENT, !IS_VOLATILE, IS_CHANGEABLE, !IS_COMPOSITE, IS_RESOLVE_PROXIES, !IS_UNSETTABLE, IS_UNIQUE, !IS_DERIVED, IS_ORDERED);
+    initEAttribute(getGenEnumLiteral_Documentation(), theEcorePackage.getEString(), "documentation", null, 0, 1, GenEnumLiteral.class, !IS_TRANSIENT, !IS_VOLATILE, IS_CHANGEABLE, IS_UNSETTABLE, !IS_ID, IS_UNIQUE, !IS_DERIVED, IS_ORDERED);
 
     initEClass(genClassifierEClass, GenClassifier.class, "GenClassifier", IS_ABSTRACT, !IS_INTERFACE, IS_GENERATED_INSTANCE_CLASS);
     initEReference(getGenClassifier_GenPackage(), this.getGenPackage(), this.getGenPackage_GenClassifiers(), "genPackage", null, 1, 1, GenClassifier.class, IS_TRANSIENT, IS_VOLATILE, !IS_CHANGEABLE, !IS_COMPOSITE, !IS_RESOLVE_PROXIES, !IS_UNSETTABLE, IS_UNIQUE, !IS_DERIVED, IS_ORDERED);
     initEReference(getGenClassifier_GenTypeParameters(), this.getGenTypeParameter(), null, "genTypeParameters", null, 0, -1, GenClassifier.class, !IS_TRANSIENT, !IS_VOLATILE, IS_CHANGEABLE, IS_COMPOSITE, !IS_RESOLVE_PROXIES, !IS_UNSETTABLE, IS_UNIQUE, !IS_DERIVED, IS_ORDERED);
+    initEAttribute(getGenClassifier_Documentation(), theEcorePackage.getEString(), "documentation", null, 0, 1, GenClassifier.class, !IS_TRANSIENT, !IS_VOLATILE, IS_CHANGEABLE, IS_UNSETTABLE, !IS_ID, IS_UNIQUE, !IS_DERIVED, IS_ORDERED);
 
     initEClass(genDataTypeEClass, GenDataType.class, "GenDataType", !IS_ABSTRACT, !IS_INTERFACE, IS_GENERATED_INSTANCE_CLASS);
     initEReference(getGenDataType_EcoreDataType(), theEcorePackage.getEDataType(), null, "ecoreDataType", null, 1, 1, GenDataType.class, !IS_TRANSIENT, !IS_VOLATILE, IS_CHANGEABLE, !IS_COMPOSITE, IS_RESOLVE_PROXIES, !IS_UNSETTABLE, IS_UNIQUE, !IS_DERIVED, IS_ORDERED);
@@ -2555,12 +2695,14 @@
     initEReference(getGenOperation_EcoreOperation(), theEcorePackage.getEOperation(), null, "ecoreOperation", null, 1, 1, GenOperation.class, !IS_TRANSIENT, !IS_VOLATILE, IS_CHANGEABLE, !IS_COMPOSITE, IS_RESOLVE_PROXIES, !IS_UNSETTABLE, IS_UNIQUE, !IS_DERIVED, IS_ORDERED);
     initEReference(getGenOperation_GenParameters(), this.getGenParameter(), this.getGenParameter_GenOperation(), "genParameters", null, 0, -1, GenOperation.class, !IS_TRANSIENT, !IS_VOLATILE, IS_CHANGEABLE, IS_COMPOSITE, !IS_RESOLVE_PROXIES, !IS_UNSETTABLE, IS_UNIQUE, !IS_DERIVED, IS_ORDERED);
     initEReference(getGenOperation_GenTypeParameters(), this.getGenTypeParameter(), null, "genTypeParameters", null, 0, -1, GenOperation.class, !IS_TRANSIENT, !IS_VOLATILE, IS_CHANGEABLE, IS_COMPOSITE, !IS_RESOLVE_PROXIES, !IS_UNSETTABLE, IS_UNIQUE, !IS_DERIVED, IS_ORDERED);
+    initEAttribute(getGenOperation_SuppressedVisibility(), theEcorePackage.getEBoolean(), "suppressedVisibility", null, 0, 1, GenOperation.class, !IS_TRANSIENT, !IS_VOLATILE, IS_CHANGEABLE, IS_UNSETTABLE, !IS_ID, IS_UNIQUE, !IS_DERIVED, IS_ORDERED);
 
     initEClass(genParameterEClass, GenParameter.class, "GenParameter", !IS_ABSTRACT, !IS_INTERFACE, IS_GENERATED_INSTANCE_CLASS);
     initEReference(getGenParameter_GenOperation(), this.getGenOperation(), this.getGenOperation_GenParameters(), "genOperation", null, 1, 1, GenParameter.class, IS_TRANSIENT, !IS_VOLATILE, IS_CHANGEABLE, !IS_COMPOSITE, !IS_RESOLVE_PROXIES, !IS_UNSETTABLE, IS_UNIQUE, !IS_DERIVED, IS_ORDERED);
     initEReference(getGenParameter_EcoreParameter(), theEcorePackage.getEParameter(), null, "ecoreParameter", null, 1, 1, GenParameter.class, !IS_TRANSIENT, !IS_VOLATILE, IS_CHANGEABLE, !IS_COMPOSITE, IS_RESOLVE_PROXIES, !IS_UNSETTABLE, IS_UNIQUE, !IS_DERIVED, IS_ORDERED);
 
     initEClass(genTypedElementEClass, GenTypedElement.class, "GenTypedElement", IS_ABSTRACT, !IS_INTERFACE, IS_GENERATED_INSTANCE_CLASS);
+    initEAttribute(getGenTypedElement_Documentation(), theEcorePackage.getEString(), "documentation", null, 0, 1, GenTypedElement.class, !IS_TRANSIENT, !IS_VOLATILE, IS_CHANGEABLE, IS_UNSETTABLE, !IS_ID, IS_UNIQUE, !IS_DERIVED, IS_ORDERED);
 
     initEClass(genAnnotationEClass, GenAnnotation.class, "GenAnnotation", !IS_ABSTRACT, !IS_INTERFACE, IS_GENERATED_INSTANCE_CLASS);
     initEAttribute(getGenAnnotation_Source(), ecorePackage.getEString(), "source", null, 0, 1, GenAnnotation.class, !IS_TRANSIENT, !IS_VOLATILE, IS_CHANGEABLE, !IS_UNSETTABLE, !IS_ID, IS_UNIQUE, !IS_DERIVED, IS_ORDERED);
@@ -2571,6 +2713,7 @@
 
     initEClass(genTypeParameterEClass, GenTypeParameter.class, "GenTypeParameter", !IS_ABSTRACT, !IS_INTERFACE, IS_GENERATED_INSTANCE_CLASS);
     initEReference(getGenTypeParameter_EcoreTypeParameter(), theEcorePackage.getETypeParameter(), null, "ecoreTypeParameter", null, 1, 1, GenTypeParameter.class, !IS_TRANSIENT, !IS_VOLATILE, IS_CHANGEABLE, !IS_COMPOSITE, IS_RESOLVE_PROXIES, !IS_UNSETTABLE, IS_UNIQUE, !IS_DERIVED, IS_ORDERED);
+    initEAttribute(getGenTypeParameter_Documentation(), theEcorePackage.getEString(), "documentation", null, 0, 1, GenTypeParameter.class, !IS_TRANSIENT, !IS_VOLATILE, IS_CHANGEABLE, IS_UNSETTABLE, !IS_ID, IS_UNIQUE, !IS_DERIVED, IS_ORDERED);
 
     // Initialize enums and add enum literals
     initEEnum(genProviderKindEEnum, GenProviderKind.class, "GenProviderKind");
diff --git a/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/impl/GenOperationImpl.java b/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/impl/GenOperationImpl.java
index 26d49bc..4cc26d6 100644
--- a/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/impl/GenOperationImpl.java
+++ b/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/impl/GenOperationImpl.java
@@ -58,6 +58,7 @@
  *   <li>{@link org.eclipse.emf.codegen.ecore.genmodel.impl.GenOperationImpl#getEcoreOperation <em>Ecore Operation</em>}</li>
  *   <li>{@link org.eclipse.emf.codegen.ecore.genmodel.impl.GenOperationImpl#getGenParameters <em>Gen Parameters</em>}</li>
  *   <li>{@link org.eclipse.emf.codegen.ecore.genmodel.impl.GenOperationImpl#getGenTypeParameters <em>Gen Type Parameters</em>}</li>
+ *   <li>{@link org.eclipse.emf.codegen.ecore.genmodel.impl.GenOperationImpl#isSuppressedVisibility <em>Suppressed Visibility</em>}</li>
  * </ul>
  *
  * @generated
@@ -95,6 +96,38 @@
   protected EList<GenTypeParameter> genTypeParameters;
 
   /**
+   * The default value of the '{@link #isSuppressedVisibility() <em>Suppressed Visibility</em>}' attribute.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @see #isSuppressedVisibility()
+   * @since 2.14
+   * @generated
+   * @ordered
+   */
+  protected static final boolean SUPPRESSED_VISIBILITY_EDEFAULT = false;
+
+  /**
+   * The cached value of the '{@link #isSuppressedVisibility() <em>Suppressed Visibility</em>}' attribute.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @see #isSuppressedVisibility()
+   * @since 2.14
+   * @generated
+   * @ordered
+   */
+  protected boolean suppressedVisibility = SUPPRESSED_VISIBILITY_EDEFAULT;
+
+  /**
+   * This is true if the Suppressed Visibility attribute has been set.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @since 2.14
+   * @generated
+   * @ordered
+   */
+  protected boolean suppressedVisibilityESet;
+
+  /**
    * <!-- begin-user-doc -->
    * <!-- end-user-doc -->
    * @generated modifiable
@@ -307,6 +340,8 @@
         return getGenParameters();
       case GenModelPackage.GEN_OPERATION__GEN_TYPE_PARAMETERS:
         return getGenTypeParameters();
+      case GenModelPackage.GEN_OPERATION__SUPPRESSED_VISIBILITY:
+        return isSuppressedVisibility();
     }
     return super.eGet(featureID, resolve, coreType);
   }
@@ -336,6 +371,9 @@
         getGenTypeParameters().clear();
         getGenTypeParameters().addAll((Collection<? extends GenTypeParameter>)newValue);
         return;
+      case GenModelPackage.GEN_OPERATION__SUPPRESSED_VISIBILITY:
+        setSuppressedVisibility((Boolean)newValue);
+        return;
     }
     super.eSet(featureID, newValue);
   }
@@ -362,6 +400,9 @@
       case GenModelPackage.GEN_OPERATION__GEN_TYPE_PARAMETERS:
         getGenTypeParameters().clear();
         return;
+      case GenModelPackage.GEN_OPERATION__SUPPRESSED_VISIBILITY:
+        unsetSuppressedVisibility();
+        return;
     }
     super.eUnset(featureID);
   }
@@ -384,10 +425,29 @@
         return genParameters != null && !genParameters.isEmpty();
       case GenModelPackage.GEN_OPERATION__GEN_TYPE_PARAMETERS:
         return genTypeParameters != null && !genTypeParameters.isEmpty();
+      case GenModelPackage.GEN_OPERATION__SUPPRESSED_VISIBILITY:
+        return isSetSuppressedVisibility();
     }
     return super.eIsSet(featureID);
   }
 
+  /**
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @generated
+   */
+  @Override
+  public String toString()
+  {
+    if (eIsProxy()) return super.toString();
+
+    StringBuilder result = new StringBuilder(super.toString());
+    result.append(" (suppressedVisibility: ");
+    if (suppressedVisibilityESet) result.append(suppressedVisibility); else result.append("<unset>");
+    result.append(')');
+    return result.toString();
+  }
+
   @Override
   public ETypedElement getEcoreTypedElement()
   {
@@ -916,6 +976,15 @@
   protected void reconcileSettings(GenOperation oldGenOperationVersion)
   {
     reconcileGenAnnotations(oldGenOperationVersion);
+    if (oldGenOperationVersion.eIsSet(GenModelPackage.Literals.GEN_TYPED_ELEMENT__DOCUMENTATION))
+    {
+      setDocumentation(oldGenOperationVersion.getDocumentation());
+    }
+
+    if (oldGenOperationVersion.eIsSet(GenModelPackage.Literals.GEN_OPERATION__SUPPRESSED_VISIBILITY))
+    {
+      setSuppressedVisibility(oldGenOperationVersion.isSuppressedVisibility());
+    }
   }
 
   public boolean reconcile()
@@ -1184,9 +1253,63 @@
     return false;
   }
 
+  /**
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @since 2.14
+   * @generated
+   */
+  public boolean isSuppressedVisibilityGen()
+  {
+    return suppressedVisibility;
+  }
+
   public boolean isSuppressedVisibility()
   {
-    return EcoreUtil.isSuppressedVisibility(getEcoreOperation());
+    return isSetSuppressedVisibility() ? isSuppressedVisibilityGen() : EcoreUtil.isSuppressedVisibility(getEcoreOperation());
+  }
+
+  /**
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @since 2.14
+   * @generated
+   */
+  public void setSuppressedVisibility(boolean newSuppressedVisibility)
+  {
+    boolean oldSuppressedVisibility = suppressedVisibility;
+    suppressedVisibility = newSuppressedVisibility;
+    boolean oldSuppressedVisibilityESet = suppressedVisibilityESet;
+    suppressedVisibilityESet = true;
+    if (eNotificationRequired())
+      eNotify(new ENotificationImpl(this, Notification.SET, GenModelPackage.GEN_OPERATION__SUPPRESSED_VISIBILITY, oldSuppressedVisibility, suppressedVisibility, !oldSuppressedVisibilityESet));
+  }
+
+  /**
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @since 2.14
+   * @generated
+   */
+  public void unsetSuppressedVisibility()
+  {
+    boolean oldSuppressedVisibility = suppressedVisibility;
+    boolean oldSuppressedVisibilityESet = suppressedVisibilityESet;
+    suppressedVisibility = SUPPRESSED_VISIBILITY_EDEFAULT;
+    suppressedVisibilityESet = false;
+    if (eNotificationRequired())
+      eNotify(new ENotificationImpl(this, Notification.UNSET, GenModelPackage.GEN_OPERATION__SUPPRESSED_VISIBILITY, oldSuppressedVisibility, SUPPRESSED_VISIBILITY_EDEFAULT, oldSuppressedVisibilityESet));
+  }
+
+  /**
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @since 2.14
+   * @generated
+   */
+  public boolean isSetSuppressedVisibility()
+  {
+    return suppressedVisibilityESet;
   }
 
   public boolean hasInvocationDelegate()
diff --git a/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/impl/GenPackageImpl.java b/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/impl/GenPackageImpl.java
index 8a75632..6e830c8 100644
--- a/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/impl/GenPackageImpl.java
+++ b/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/impl/GenPackageImpl.java
@@ -24,6 +24,7 @@
 import java.util.LinkedHashMap;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 import java.util.Set;
 import java.util.regex.Pattern;
@@ -127,6 +128,7 @@
  *   <li>{@link org.eclipse.emf.codegen.ecore.genmodel.impl.GenPackageImpl#getNestedGenPackages <em>Nested Gen Packages</em>}</li>
  *   <li>{@link org.eclipse.emf.codegen.ecore.genmodel.impl.GenPackageImpl#getGenClassifiers <em>Gen Classifiers</em>}</li>
  *   <li>{@link org.eclipse.emf.codegen.ecore.genmodel.impl.GenPackageImpl#getPublicationLocation <em>Publication Location</em>}</li>
+ *   <li>{@link org.eclipse.emf.codegen.ecore.genmodel.impl.GenPackageImpl#getDocumentation <em>Documentation</em>}</li>
  * </ul>
  *
  * @generated
@@ -646,6 +648,38 @@
   protected String publicationLocation = PUBLICATION_LOCATION_EDEFAULT;
 
   /**
+   * The default value of the '{@link #getDocumentation() <em>Documentation</em>}' attribute.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @see #getDocumentation()
+   * @since 2.14
+   * @generated
+   * @ordered
+   */
+  protected static final String DOCUMENTATION_EDEFAULT = null;
+
+  /**
+   * The cached value of the '{@link #getDocumentation() <em>Documentation</em>}' attribute.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @see #getDocumentation()
+   * @since 2.14
+   * @generated
+   * @ordered
+   */
+  protected String documentation = DOCUMENTATION_EDEFAULT;
+
+  /**
+   * This is true if the Documentation attribute has been set.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @since 2.14
+   * @generated
+   * @ordered
+   */
+  protected boolean documentationESet;
+
+  /**
    * <!-- begin-user-doc -->
    * <!-- end-user-doc -->
    * @generated modifiable
@@ -1187,7 +1221,8 @@
   {
     if (fileExtensions == null)
     {
-      return getPrefix().toLowerCase(getGenModel().getLocale());
+      GenModel genModel = getGenModel();
+      return getPrefix().toLowerCase(genModel == null ? Locale.getDefault() : genModel.getLocale());
     }
     return COMMA_SEPARATOR_PATTERN.matcher(fileExtensions).replaceAll(",");
   }
@@ -1437,6 +1472,66 @@
   /**
    * <!-- begin-user-doc -->
    * <!-- end-user-doc -->
+   * @since 2.14
+   * @generated
+   */
+  public String getDocumentationGen()
+  {
+    return documentation;
+  }
+
+  @Override
+  public String getDocumentation()
+  {
+    return isSetDocumentation() ? getDocumentationGen() : super.getDocumentation();
+  }
+
+  /**
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @since 2.14
+   * @generated
+   */
+  public void setDocumentation(String newDocumentation)
+  {
+    String oldDocumentation = documentation;
+    documentation = newDocumentation;
+    boolean oldDocumentationESet = documentationESet;
+    documentationESet = true;
+    if (eNotificationRequired())
+      eNotify(new ENotificationImpl(this, Notification.SET, GenModelPackage.GEN_PACKAGE__DOCUMENTATION, oldDocumentation, documentation, !oldDocumentationESet));
+  }
+
+  /**
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @since 2.14
+   * @generated
+   */
+  public void unsetDocumentation()
+  {
+    String oldDocumentation = documentation;
+    boolean oldDocumentationESet = documentationESet;
+    documentation = DOCUMENTATION_EDEFAULT;
+    documentationESet = false;
+    if (eNotificationRequired())
+      eNotify(new ENotificationImpl(this, Notification.UNSET, GenModelPackage.GEN_PACKAGE__DOCUMENTATION, oldDocumentation, DOCUMENTATION_EDEFAULT, oldDocumentationESet));
+  }
+
+  /**
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @since 2.14
+   * @generated
+   */
+  public boolean isSetDocumentation()
+  {
+    return documentationESet;
+  }
+
+  /**
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
    * @generated
    */
   @Override
@@ -1563,6 +1658,8 @@
         return getGenClassifiers();
       case GenModelPackage.GEN_PACKAGE__PUBLICATION_LOCATION:
         return getPublicationLocation();
+      case GenModelPackage.GEN_PACKAGE__DOCUMENTATION:
+        return getDocumentation();
     }
     return super.eGet(featureID, resolve, coreType);
   }
@@ -1669,6 +1766,9 @@
       case GenModelPackage.GEN_PACKAGE__PUBLICATION_LOCATION:
         setPublicationLocation((String)newValue);
         return;
+      case GenModelPackage.GEN_PACKAGE__DOCUMENTATION:
+        setDocumentation((String)newValue);
+        return;
     }
     super.eSet(featureID, newValue);
   }
@@ -1770,6 +1870,9 @@
       case GenModelPackage.GEN_PACKAGE__PUBLICATION_LOCATION:
         setPublicationLocation(PUBLICATION_LOCATION_EDEFAULT);
         return;
+      case GenModelPackage.GEN_PACKAGE__DOCUMENTATION:
+        unsetDocumentation();
+        return;
     }
     super.eUnset(featureID);
   }
@@ -1844,6 +1947,8 @@
         return !getGenClassifiers().isEmpty();
       case GenModelPackage.GEN_PACKAGE__PUBLICATION_LOCATION:
         return PUBLICATION_LOCATION_EDEFAULT == null ? publicationLocation != null : !PUBLICATION_LOCATION_EDEFAULT.equals(publicationLocation);
+      case GenModelPackage.GEN_PACKAGE__DOCUMENTATION:
+        return isSetDocumentation();
     }
     return super.eIsSet(featureID);
   }
@@ -1905,6 +2010,8 @@
     result.append(fileExtensions);
     result.append(", publicationLocation: ");
     result.append(publicationLocation);
+    result.append(", documentation: ");
+    if (documentationESet) result.append(documentation); else result.append("<unset>");
     result.append(')');
     return result.toString();
   }
@@ -4131,6 +4238,11 @@
     reconcileGenAnnotations(oldGenPackageVersion);
 
     setPublicationLocation(oldGenPackageVersion.getPublicationLocation());
+
+    if (oldGenPackageVersion.eIsSet(GenModelPackage.Literals.GEN_PACKAGE__DOCUMENTATION))
+    {
+      setDocumentation(oldGenPackageVersion.getDocumentation());
+    }
   }
 
   public boolean reconcile()
diff --git a/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/impl/GenParameterImpl.java b/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/impl/GenParameterImpl.java
index 67a0a2b..73496f4 100644
--- a/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/impl/GenParameterImpl.java
+++ b/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/impl/GenParameterImpl.java
@@ -389,6 +389,10 @@
   protected void reconcileSettings(GenParameter oldGenParameterVersion)
   {
     reconcileGenAnnotations(oldGenParameterVersion);
+    if (oldGenParameterVersion.eIsSet(GenModelPackage.Literals.GEN_TYPED_ELEMENT__DOCUMENTATION))
+    {
+      setDocumentation(oldGenParameterVersion.getDocumentation());
+    }
   }
 
   public boolean reconcile()
diff --git a/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/impl/GenTypeParameterImpl.java b/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/impl/GenTypeParameterImpl.java
index 367c894..146341f 100644
--- a/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/impl/GenTypeParameterImpl.java
+++ b/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/impl/GenTypeParameterImpl.java
@@ -32,6 +32,7 @@
  * </p>
  * <ul>
  *   <li>{@link org.eclipse.emf.codegen.ecore.genmodel.impl.GenTypeParameterImpl#getEcoreTypeParameter <em>Ecore Type Parameter</em>}</li>
+ *   <li>{@link org.eclipse.emf.codegen.ecore.genmodel.impl.GenTypeParameterImpl#getDocumentation <em>Documentation</em>}</li>
  * </ul>
  *
  * @generated
@@ -48,6 +49,35 @@
    */
   protected ETypeParameter ecoreTypeParameter;
   /**
+   * The default value of the '{@link #getDocumentation() <em>Documentation</em>}' attribute.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @see #getDocumentation()
+   * @since 2.14
+   * @generated
+   * @ordered
+   */
+  protected static final String DOCUMENTATION_EDEFAULT = null;
+  /**
+   * The cached value of the '{@link #getDocumentation() <em>Documentation</em>}' attribute.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @see #getDocumentation()
+   * @since 2.14
+   * @generated
+   * @ordered
+   */
+  protected String documentation = DOCUMENTATION_EDEFAULT;
+  /**
+   * This is true if the Documentation attribute has been set.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @since 2.14
+   * @generated
+   * @ordered
+   */
+  protected boolean documentationESet;
+  /**
    * <!-- begin-user-doc -->
    * <!-- end-user-doc -->
    * @generated
@@ -114,6 +144,66 @@
   /**
    * <!-- begin-user-doc -->
    * <!-- end-user-doc -->
+   * @since 2.14
+   * @generated
+   */
+  public String getDocumentationGen()
+  {
+    return documentation;
+  }
+
+  @Override
+  public String getDocumentation()
+  {
+    return isSetDocumentation() ? getDocumentationGen() : super.getDocumentation();
+  }
+
+  /**
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @since 2.14
+   * @generated
+   */
+  public void setDocumentation(String newDocumentation)
+  {
+    String oldDocumentation = documentation;
+    documentation = newDocumentation;
+    boolean oldDocumentationESet = documentationESet;
+    documentationESet = true;
+    if (eNotificationRequired())
+      eNotify(new ENotificationImpl(this, Notification.SET, GenModelPackage.GEN_TYPE_PARAMETER__DOCUMENTATION, oldDocumentation, documentation, !oldDocumentationESet));
+  }
+
+  /**
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @since 2.14
+   * @generated
+   */
+  public void unsetDocumentation()
+  {
+    String oldDocumentation = documentation;
+    boolean oldDocumentationESet = documentationESet;
+    documentation = DOCUMENTATION_EDEFAULT;
+    documentationESet = false;
+    if (eNotificationRequired())
+      eNotify(new ENotificationImpl(this, Notification.UNSET, GenModelPackage.GEN_TYPE_PARAMETER__DOCUMENTATION, oldDocumentation, DOCUMENTATION_EDEFAULT, oldDocumentationESet));
+  }
+
+  /**
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @since 2.14
+   * @generated
+   */
+  public boolean isSetDocumentation()
+  {
+    return documentationESet;
+  }
+
+  /**
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
    * @generated
    */
   @Override
@@ -124,6 +214,8 @@
       case GenModelPackage.GEN_TYPE_PARAMETER__ECORE_TYPE_PARAMETER:
         if (resolve) return getEcoreTypeParameter();
         return basicGetEcoreTypeParameter();
+      case GenModelPackage.GEN_TYPE_PARAMETER__DOCUMENTATION:
+        return getDocumentation();
     }
     return super.eGet(featureID, resolve, coreType);
   }
@@ -141,6 +233,9 @@
       case GenModelPackage.GEN_TYPE_PARAMETER__ECORE_TYPE_PARAMETER:
         setEcoreTypeParameter((ETypeParameter)newValue);
         return;
+      case GenModelPackage.GEN_TYPE_PARAMETER__DOCUMENTATION:
+        setDocumentation((String)newValue);
+        return;
     }
     super.eSet(featureID, newValue);
   }
@@ -158,6 +253,9 @@
       case GenModelPackage.GEN_TYPE_PARAMETER__ECORE_TYPE_PARAMETER:
         setEcoreTypeParameter((ETypeParameter)null);
         return;
+      case GenModelPackage.GEN_TYPE_PARAMETER__DOCUMENTATION:
+        unsetDocumentation();
+        return;
     }
     super.eUnset(featureID);
   }
@@ -174,10 +272,29 @@
     {
       case GenModelPackage.GEN_TYPE_PARAMETER__ECORE_TYPE_PARAMETER:
         return ecoreTypeParameter != null;
+      case GenModelPackage.GEN_TYPE_PARAMETER__DOCUMENTATION:
+        return isSetDocumentation();
     }
     return super.eIsSet(featureID);
   }
 
+  /**
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @generated
+   */
+  @Override
+  public String toString()
+  {
+    if (eIsProxy()) return super.toString();
+
+    StringBuilder result = new StringBuilder(super.toString());
+    result.append(" (documentation: ");
+    if (documentationESet) result.append(documentation); else result.append("<unset>");
+    result.append(')');
+    return result.toString();
+  }
+
   @Override
   public String getName()
   {
@@ -202,6 +319,10 @@
   protected void reconcileSettings(GenTypeParameter oldGenTypeParameterVersion)
   {
     reconcileGenAnnotations(oldGenTypeParameterVersion);
+    if (oldGenTypeParameterVersion.eIsSet(GenModelPackage.Literals.GEN_TYPE_PARAMETER__DOCUMENTATION))
+    {
+      setDocumentation(oldGenTypeParameterVersion.getDocumentation());
+    }
   }
 
   public boolean reconcile()
diff --git a/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/impl/GenTypedElementImpl.java b/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/impl/GenTypedElementImpl.java
index bf90f6f..a995b14 100644
--- a/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/impl/GenTypedElementImpl.java
+++ b/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/impl/GenTypedElementImpl.java
@@ -20,6 +20,7 @@
 import org.eclipse.emf.codegen.ecore.genmodel.GenPackage;
 import org.eclipse.emf.codegen.ecore.genmodel.GenTypedElement;
 import org.eclipse.emf.codegen.util.CodeGenUtil;
+import org.eclipse.emf.common.notify.Notification;
 import org.eclipse.emf.common.util.Diagnostic;
 import org.eclipse.emf.common.util.EList;
 
@@ -33,6 +34,7 @@
 import org.eclipse.emf.ecore.EStructuralFeature;
 import org.eclipse.emf.ecore.ETypeParameter;
 import org.eclipse.emf.ecore.ETypedElement;
+import org.eclipse.emf.ecore.impl.ENotificationImpl;
 import org.eclipse.emf.ecore.util.EcoreUtil;
 import org.eclipse.emf.ecore.util.EcoreValidator;
 import org.eclipse.emf.ecore.xml.type.XMLTypePackage;
@@ -41,12 +43,49 @@
  * <!-- begin-user-doc -->
  * An implementation of the model object '<em><b>Gen Typed Element</b></em>'.
  * <!-- end-user-doc -->
+ * <p>
+ * The following features are implemented:
+ * </p>
+ * <ul>
+ *   <li>{@link org.eclipse.emf.codegen.ecore.genmodel.impl.GenTypedElementImpl#getDocumentation <em>Documentation</em>}</li>
+ * </ul>
  *
  * @generated
  */
 public abstract class GenTypedElementImpl extends GenBaseImpl implements GenTypedElement
 {
   /**
+   * The default value of the '{@link #getDocumentation() <em>Documentation</em>}' attribute.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @see #getDocumentation()
+   * @since 2.14
+   * @generated
+   * @ordered
+   */
+  protected static final String DOCUMENTATION_EDEFAULT = null;
+  /**
+   * The cached value of the '{@link #getDocumentation() <em>Documentation</em>}' attribute.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @see #getDocumentation()
+   * @since 2.14
+   * @generated
+   * @ordered
+   */
+  protected String documentation = DOCUMENTATION_EDEFAULT;
+
+  /**
+   * This is true if the Documentation attribute has been set.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @since 2.14
+   * @generated
+   * @ordered
+   */
+  protected boolean documentationESet;
+
+  /**
    * <!-- begin-user-doc -->
    * <!-- end-user-doc -->
    * @generated
@@ -67,6 +106,149 @@
     return GenModelPackage.Literals.GEN_TYPED_ELEMENT;
   }
 
+  /**
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @since 2.14
+   * @generated
+   */
+  public String getDocumentationGen()
+  {
+    return documentation;
+  }
+
+  @Override
+  public String getDocumentation()
+  {
+    return isSetDocumentation() ? getDocumentationGen() : super.getDocumentation();
+  }
+
+  /**
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @since 2.14
+   * @generated
+   */
+  public void setDocumentation(String newDocumentation)
+  {
+    String oldDocumentation = documentation;
+    documentation = newDocumentation;
+    boolean oldDocumentationESet = documentationESet;
+    documentationESet = true;
+    if (eNotificationRequired())
+      eNotify(new ENotificationImpl(this, Notification.SET, GenModelPackage.GEN_TYPED_ELEMENT__DOCUMENTATION, oldDocumentation, documentation, !oldDocumentationESet));
+  }
+
+  /**
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @since 2.14
+   * @generated
+   */
+  public void unsetDocumentation()
+  {
+    String oldDocumentation = documentation;
+    boolean oldDocumentationESet = documentationESet;
+    documentation = DOCUMENTATION_EDEFAULT;
+    documentationESet = false;
+    if (eNotificationRequired())
+      eNotify(new ENotificationImpl(this, Notification.UNSET, GenModelPackage.GEN_TYPED_ELEMENT__DOCUMENTATION, oldDocumentation, DOCUMENTATION_EDEFAULT, oldDocumentationESet));
+  }
+
+  /**
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @since 2.14
+   * @generated
+   */
+  public boolean isSetDocumentation()
+  {
+    return documentationESet;
+  }
+
+  /**
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @generated
+   */
+  @Override
+  public Object eGet(int featureID, boolean resolve, boolean coreType)
+  {
+    switch (featureID)
+    {
+      case GenModelPackage.GEN_TYPED_ELEMENT__DOCUMENTATION:
+        return getDocumentation();
+    }
+    return super.eGet(featureID, resolve, coreType);
+  }
+
+  /**
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @generated
+   */
+  @Override
+  public void eSet(int featureID, Object newValue)
+  {
+    switch (featureID)
+    {
+      case GenModelPackage.GEN_TYPED_ELEMENT__DOCUMENTATION:
+        setDocumentation((String)newValue);
+        return;
+    }
+    super.eSet(featureID, newValue);
+  }
+
+  /**
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @generated
+   */
+  @Override
+  public void eUnset(int featureID)
+  {
+    switch (featureID)
+    {
+      case GenModelPackage.GEN_TYPED_ELEMENT__DOCUMENTATION:
+        unsetDocumentation();
+        return;
+    }
+    super.eUnset(featureID);
+  }
+
+  /**
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @generated
+   */
+  @Override
+  public boolean eIsSet(int featureID)
+  {
+    switch (featureID)
+    {
+      case GenModelPackage.GEN_TYPED_ELEMENT__DOCUMENTATION:
+        return isSetDocumentation();
+    }
+    return super.eIsSet(featureID);
+  }
+
+  /**
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @generated
+   */
+  @Override
+  public String toString()
+  {
+    if (eIsProxy()) return super.toString();
+
+    StringBuilder result = new StringBuilder(super.toString());
+    result.append(" (documentation: ");
+    if (documentationESet) result.append(documentation); else result.append("<unset>");
+    result.append(')');
+    return result.toString();
+  }
+
   public abstract ETypedElement getEcoreTypedElement();
 
   @Override
diff --git a/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/util/GenModelAnnotatonValidator.java b/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/util/GenModelAnnotatonValidator.java
new file mode 100644
index 0000000..10b2194
--- /dev/null
+++ b/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/util/GenModelAnnotatonValidator.java
@@ -0,0 +1,279 @@
+/**
+ * Copyright (c) 2017 Eclipse contributors and others.
+ * All rights reserved.   This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.eclipse.emf.codegen.ecore.genmodel.util;
+
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.eclipse.emf.codegen.ecore.CodeGenEcorePlugin;
+import org.eclipse.emf.codegen.ecore.genmodel.GenBase;
+import org.eclipse.emf.codegen.ecore.genmodel.GenFeature;
+import org.eclipse.emf.codegen.ecore.genmodel.GenModel;
+import org.eclipse.emf.codegen.ecore.genmodel.GenModelPackage;
+import org.eclipse.emf.codegen.ecore.genmodel.GenPackage;
+import org.eclipse.emf.codegen.ecore.genmodel.impl.GenModelImpl;
+import org.eclipse.emf.codegen.util.CodeGenUtil;
+import org.eclipse.emf.common.util.Diagnostic;
+import org.eclipse.emf.common.util.DiagnosticChain;
+import org.eclipse.emf.common.util.ResourceLocator;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.EAnnotation;
+import org.eclipse.emf.ecore.EAttribute;
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EDataType;
+import org.eclipse.emf.ecore.EEnum;
+import org.eclipse.emf.ecore.EEnumLiteral;
+import org.eclipse.emf.ecore.EModelElement;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EOperation;
+import org.eclipse.emf.ecore.EPackage;
+import org.eclipse.emf.ecore.EParameter;
+import org.eclipse.emf.ecore.EReference;
+import org.eclipse.emf.ecore.EStructuralFeature;
+import org.eclipse.emf.ecore.ETypeParameter;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.emf.ecore.resource.impl.ResourceImpl;
+import org.eclipse.emf.ecore.util.BasicEAnnotationValidator;
+import org.eclipse.emf.ecore.util.EcoreSwitch;
+import org.eclipse.emf.ecore.util.EcoreUtil;
+
+
+/**
+ * An annotation validator for {@link EcoreUtil#GEN_MODEL_ANNOTATION_URI GenModel} annotations.
+ *
+ * @since 2.14
+ * @see GenModelPackage#eNS_URI
+ */
+public final class GenModelAnnotatonValidator extends BasicEAnnotationValidator
+{
+  /**
+   * @see #validateReferenceDetailLiteralValue(EAnnotation, EModelElement, Entry, EReference, List, DiagnosticChain, Map)
+   */
+  public static final int INVALID_VALUE_LITERAL = BasicEAnnotationValidator.INVALID_VALUE_LITERAL;
+
+  public static final GenModelAnnotatonValidator INSTANCE = new GenModelAnnotatonValidator();
+
+  public static final String DIAGNOSTIC_SOURCE = "org.eclipse.emf.codegen.ecore.genmodel.annotation";
+
+  public GenModelAnnotatonValidator()
+  {
+    super(GenModelPackage.eNS_URI, "GenModel", DIAGNOSTIC_SOURCE);
+  }
+
+  @Override
+  protected boolean isValidLocation(EAnnotation eAnnotation, EModelElement eModelElement)
+  {
+    return !getProperties(eModelElement).isEmpty();
+  }
+
+  @Override
+  protected boolean validateReferenceDetailLiteralValue(
+    EAnnotation eAnnotation,
+    EModelElement eModelElement,
+    Entry<String, String> entry,
+    EReference reference,
+    List<Object> values,
+    DiagnosticChain diagnostics,
+    Map<Object, Object> context)
+  {
+    String value = entry.getValue();
+    boolean result = false;
+    if (value != null)
+    {
+      EClass eClass = (EClass)eModelElement;
+      for (EAttribute eAttribute : eClass.getEAllAttributes())
+      {
+        if (value.equals(eAttribute.getName()))
+        {
+          values.add(eAttribute);
+          result = true;
+          break;
+        }
+      }
+    }
+
+    if (!result && diagnostics != null)
+    {
+      diagnostics.add(
+        createDiagnostic(
+          Diagnostic.WARNING,
+          INVALID_VALUE_LITERAL,
+          getString(getResourceLocator(), "_UI_InvalidAnnotationLabelEntryValue_diagnostic", value),
+          value,
+          reference.getEReferenceType(),
+          reference));
+    }
+
+    return result;
+  }
+
+  @Override
+  protected List<EClass> getPropertyClasses(EModelElement eModelElement)
+  {
+    final List<EClass> result = new ArrayList<EClass>();
+    new PropertySwitch()
+      {
+        @Override
+        protected void addFeatures(EClass eClass)
+        {
+          result.add(eClass);
+        }
+      }.doSwitch(eModelElement);
+    return Collections.unmodifiableList(result);
+  }
+
+  @Override
+  protected boolean isIncludedProperty(EModelElement eModelElement, EClass eClass, EStructuralFeature eStructuralFeature)
+  {
+    return eStructuralFeature instanceof EAttribute || eStructuralFeature == GenModelPackage.Literals.GEN_CLASS__LABEL_FEATURE;
+  }
+
+  @Override
+  protected EObject initialize(EObject eObject, EAnnotation eAnnotation)
+  {
+    final GenBase genBase = (GenBase)eObject;
+    final EModelElement eModelElement = eAnnotation.getEModelElement();
+    EClass eClass = genBase.eClass();
+    EStructuralFeature eStructuralFeature = eClass.getEStructuralFeature("ecore" + eClass.getName().substring(3));
+    if (eStructuralFeature != null)
+    {
+      genBase.eSet(eStructuralFeature, eModelElement);
+      if (eModelElement instanceof EPackage)
+      {
+        EPackage ePackage = (EPackage)eModelElement;
+        String name = ePackage.getName();
+        if (name != null)
+        {
+          ((GenPackage)genBase).setPrefix(CodeGenUtil.capName(name));
+        }
+      }
+    }
+    else
+    {
+      GenPackage genPackage = (GenPackage)createInstance(GenModelPackage.Literals.GEN_PACKAGE, eAnnotation);
+      GenModel genModel = (GenModel)genBase;
+      genModel.getGenPackages().add(genPackage);
+      Resource resource = eModelElement.eResource();
+      if (resource != null)
+      {
+        URI uri = resource.getURI();
+        if (uri != null)
+        {
+          Resource genModelResource = new ResourceImpl(uri.trimFileExtension().appendFileExtension("genmodel"));
+          genModelResource.getContents().add(genModel);
+        }
+      }
+      genModel.initialize(false);
+    }
+
+    new GenModelImpl()
+      {
+        {
+          handleAnnotations((GenBase)genBase, eModelElement);
+        }
+      };
+
+    return genBase;
+  }
+
+  @Override
+  protected String convertPropertyReferenceValueToLiteralItem(EObject eObject, EReference eReference, Object value)
+  {
+    if (value instanceof GenFeature)
+    {
+      GenFeature genFeature = (GenFeature)value;
+      return genFeature.getEcoreFeature().getName();
+    }
+    else
+    {
+      return super.convertPropertyReferenceValueToLiteralItem(eObject, eReference, value);
+    }
+  }
+
+  @Override
+  protected ResourceLocator getResourceLocator()
+  {
+    return CodeGenEcorePlugin.INSTANCE;
+  }
+
+  private static abstract class PropertySwitch extends EcoreSwitch<Void>
+  {
+    protected abstract void addFeatures(EClass eClass);
+
+    @Override
+    public Void caseEStructuralFeature(EStructuralFeature eStructuralFeature)
+    {
+      addFeatures(GenModelPackage.Literals.GEN_FEATURE);
+      return null;
+    }
+
+    @Override
+    public Void caseEClass(EClass eClass)
+    {
+      addFeatures(GenModelPackage.Literals.GEN_CLASS);
+      return null;
+    }
+
+    @Override
+    public Void caseEDataType(EDataType eDataType)
+    {
+      if (!(eDataType instanceof EEnum))
+      {
+        addFeatures(GenModelPackage.Literals.GEN_DATA_TYPE);
+      }
+      return null;
+    }
+
+    @Override
+    public Void caseEParameter(EParameter eParameter)
+    {
+      addFeatures(GenModelPackage.Literals.GEN_PARAMETER);
+      return null;
+    }
+
+    @Override
+    public Void caseEOperation(EOperation eOperation)
+    {
+      addFeatures(GenModelPackage.Literals.GEN_OPERATION);
+      return null;
+    }
+
+    @Override
+    public Void caseEPackage(EPackage ePackage)
+    {
+      addFeatures(GenModelPackage.Literals.GEN_PACKAGE);
+      addFeatures(GenModelPackage.Literals.GEN_MODEL);
+      return null;
+    }
+
+    @Override
+    public Void caseEEnumLiteral(EEnumLiteral eEnumLiteral)
+    {
+      addFeatures(GenModelPackage.Literals.GEN_ENUM_LITERAL);
+      return null;
+    }
+
+    @Override
+    public Void caseEEnum(EEnum eEnum)
+    {
+      addFeatures(GenModelPackage.Literals.GEN_ENUM);
+      return null;
+    }
+
+    @Override
+    public Void caseETypeParameter(ETypeParameter eTypeParameter)
+    {
+      addFeatures(GenModelPackage.Literals.GEN_TYPE_PARAMETER);
+      return null;
+    }
+  }
+}
\ No newline at end of file
diff --git a/plugins/org.eclipse.emf.codegen/src/org/eclipse/emf/codegen/jet/JETCompiler.java b/plugins/org.eclipse.emf.codegen/src/org/eclipse/emf/codegen/jet/JETCompiler.java
index 303d37d..6838f55 100644
--- a/plugins/org.eclipse.emf.codegen/src/org/eclipse/emf/codegen/jet/JETCompiler.java
+++ b/plugins/org.eclipse.emf.codegen/src/org/eclipse/emf/codegen/jet/JETCompiler.java
@@ -59,16 +59,19 @@
     {
       private final Map<String, JETConstantDataGenerator> delegate = new HashMap<String, JETConstantDataGenerator>(100, 100);
 
+      @Override
       public JETConstantDataGenerator put(char[] key, JETConstantDataGenerator value)
       {
         return delegate.put(new String(key), value);
       }
 
+      @Override
       public JETConstantDataGenerator get(Object key)
       {
         return delegate.get(key instanceof char[] ? new String((char[])key) : key);
       }
 
+      @Override
       public int size()
       {
         return delegate.size();
@@ -80,6 +83,7 @@
         return
           new AbstractSet<Map.Entry<char[], JETConstantDataGenerator>>()
           {
+            @Override
             public Iterator<Map.Entry<char[],JETConstantDataGenerator>> iterator()
             {
               return new Iterator<Map.Entry<char[],JETConstantDataGenerator>>()
diff --git a/plugins/org.eclipse.emf.common.ui/src/org/eclipse/emf/common/ui/celleditor/ExtendedComboBoxCellEditor.java b/plugins/org.eclipse.emf.common.ui/src/org/eclipse/emf/common/ui/celleditor/ExtendedComboBoxCellEditor.java
index c8d43d8..b768d92 100644
--- a/plugins/org.eclipse.emf.common.ui/src/org/eclipse/emf/common/ui/celleditor/ExtendedComboBoxCellEditor.java
+++ b/plugins/org.eclipse.emf.common.ui/src/org/eclipse/emf/common/ui/celleditor/ExtendedComboBoxCellEditor.java
@@ -11,6 +11,7 @@
 package org.eclipse.emf.common.ui.celleditor;
 
 
+import java.text.MessageFormat;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Comparator;
@@ -18,15 +19,24 @@
 
 import org.eclipse.emf.common.CommonPlugin;
 import org.eclipse.jface.viewers.ComboBoxCellEditor;
+import org.eclipse.jface.viewers.ICellEditorValidator;
 import org.eclipse.jface.viewers.ILabelProvider;
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.custom.CCombo;
+import org.eclipse.swt.events.FocusAdapter;
 import org.eclipse.swt.events.FocusEvent;
 import org.eclipse.swt.events.FocusListener;
 import org.eclipse.swt.events.KeyEvent;
 import org.eclipse.swt.events.KeyListener;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.MouseTrackAdapter;
+import org.eclipse.swt.graphics.Point;
 import org.eclipse.swt.widgets.Composite;
 import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Listener;
 
 
 /**
@@ -35,6 +45,17 @@
  */
 public class ExtendedComboBoxCellEditor extends ComboBoxCellEditor
 {
+  /**
+   * A handler for providing validation feedback and for converting from literal values to instances values.
+   *
+   * @since 2.14
+   */
+  public interface ValueHandler
+  {
+    String isValid(String text);
+    Object toValue(String text);
+  }
+
   private static class StringPositionPair implements Comparable<StringPositionPair>
   {
     Comparator<String> comparator = CommonPlugin.INSTANCE.getComparator();
@@ -173,32 +194,155 @@
 
   protected boolean sorted;
 
+  /**
+   * @since 2.14
+   */
+  protected boolean autoShowDropDownList;
+
+  private boolean mouseInCombo;
+
   public ExtendedComboBoxCellEditor(Composite composite, List<?> list, ILabelProvider labelProvider)
   {
-    this(composite, list, labelProvider, false, SWT.READ_ONLY);
+    this(composite, list, labelProvider, false, SWT.READ_ONLY, null, false);
   }
 
   public ExtendedComboBoxCellEditor(Composite composite, List<?> list, ILabelProvider labelProvider, boolean sorted)
   {
-    this(composite, list, labelProvider, sorted, SWT.READ_ONLY);
+    this(composite, list, labelProvider, sorted, SWT.READ_ONLY, null, false);
   }
 
   public ExtendedComboBoxCellEditor(Composite composite, List<?> list, ILabelProvider labelProvider, int style)
   {
-    this(composite, list, labelProvider, false, style);
+    this(composite, list, labelProvider, false, style, null, false);
   }
 
   public ExtendedComboBoxCellEditor(Composite composite, List<?> list, ILabelProvider labelProvider, boolean sorted, int style)
   {
+    this(composite, list, labelProvider, sorted, style, null, false);
+  }
+
+  /**
+   * This constructor is useful for creating a cell editor that supports both choices of values as well as direct entry of a value in the text field.
+   *
+   * @since 2.14
+   */
+  public ExtendedComboBoxCellEditor(Composite composite, List<?> list, ILabelProvider labelProvider, boolean sorted, int style, final ValueHandler valueHandler, boolean autoShowDropDownList)
+  {
     super(composite, createItems(sorted ? list = new ArrayList<Object>(list) : list, labelProvider, null, sorted), style);
     this.originalList = list;
     this.list = list;
     this.labelProvider = labelProvider;
     this.sorted = sorted;
+    this.autoShowDropDownList = autoShowDropDownList;
+    final CCombo combo = (CCombo)getControl();
     if ((style & SWT.READ_ONLY) != 0)
     {
       new FilteringAdapter(getControl());
+
+      // Clicking in the text area while the drop down list is showing, will cause the drop down to disappear and reappear.
+      // If we keep track of the very short time between the focus lost and the mouse down event, we can avoid that.
+      class DropDownAvoider extends FocusAdapter implements Listener
+      {
+        private long focusLostTime;
+
+        @Override
+        public void focusLost(FocusEvent e)
+        {
+          focusLostTime = System.currentTimeMillis();
+        }
+
+        public void handleEvent(Event event)
+        {
+          if (System.currentTimeMillis() - focusLostTime < 100)
+          {
+            event.doit = false;
+          }
+        }
+      }
+
+      DropDownAvoider dopDownAvoider = new DropDownAvoider();
+      combo.addListener(SWT.MouseDown, dopDownAvoider);
+      combo.addFocusListener(dopDownAvoider);
     }
+    else if (valueHandler != null)
+    {
+      setValidator(new ICellEditorValidator()
+        {
+          public String isValid(Object value)
+          {
+            return valueHandler.isValid((String)value);
+          }
+        });
+
+      combo.addModifyListener
+        (new ModifyListener()
+         {
+          boolean updating;
+
+          public void modifyText(ModifyEvent e)
+          {
+            if (!updating)
+            {
+              updating = true;
+
+              String text = combo.getText();
+              ArrayList<Object> newList = new ArrayList<Object>(originalList);
+              Object valueToSelect = null;
+
+              try
+              {
+                valueToSelect = valueHandler.toValue(text);
+                if (!newList.contains(valueToSelect))
+                {
+                  newList.add(0, valueToSelect);
+                }
+              }
+              catch (RuntimeException exception)
+              {
+                // Ignore.
+              }
+
+              String[] items = createItems(newList, ExtendedComboBoxCellEditor.this.labelProvider, null, ExtendedComboBoxCellEditor.this.sorted);
+              ExtendedComboBoxCellEditor.this.list = newList;
+              combo.setItems(items);
+              combo.notifyListeners(SWT.Selection, new Event());
+              combo.setRedraw(false);
+              Point selection = combo.getSelection();
+              if (ExtendedComboBoxCellEditor.this.list.contains(valueToSelect))
+              {
+                setValue(valueToSelect);
+              }
+              else if (!ExtendedComboBoxCellEditor.this.list.isEmpty())
+              {
+                setValue(ExtendedComboBoxCellEditor.this.list.get(0));
+              }
+              combo.setText(text);
+              combo.setSelection(selection);
+              String oldErrorMessage = getErrorMessage();
+              String newErrorMessage = valueHandler.isValid(text);
+              setErrorMessage(newErrorMessage == null ? null : MessageFormat.format(newErrorMessage, new Object[0]));
+              fireEditorValueChanged(oldErrorMessage == null, newErrorMessage == null);
+              combo.setRedraw(true);
+              updating = false;
+            }
+          }
+         });
+    }
+
+    combo.addMouseTrackListener(new MouseTrackAdapter()
+      {
+        @Override
+        public void mouseExit(MouseEvent e)
+        {
+          mouseInCombo = false;
+        }
+
+        @Override
+        public void mouseEnter(MouseEvent e)
+        {
+          mouseInCombo = true;
+        }
+      });
   }
 
   protected void refreshItems(String filter)
@@ -225,6 +369,22 @@
     }
   }
 
+  /**
+   * When the drop down button is clicked while the drop down list is showing,
+   * the focus goes to the shell, but the cell editor will get focus again so hasn't really lost focus for long.
+   * We track whether the mouse is currently in the combo and ignore focus lost in this case.
+   */
+  @Override
+  protected void focusLost()
+  {
+    if (!mouseInCombo)
+    {
+      // Send one more event to ensure that the current text is selected at the right index in the list.
+      ((CCombo)getControl()).notifyListeners(SWT.Modify, null);
+      super.focusLost();
+    }
+  }
+
   @Override
   public Object doGetValue()
   {
@@ -240,12 +400,29 @@
     // Set the index of the object value in the list via this call to super.
     //
     int index = list.indexOf(value);
+    if (index == -1 && value != null)
+    {
+      // Look for the item textually.
+      String text = labelProvider.getText(value);
+      index = Arrays.asList(getItems()).indexOf(text);
+    }
     if (index != -1)
     {
       super.doSetValue(index);
     }
   }
 
+  @Override
+  public void setFocus()
+  {
+    super.setFocus();
+
+    if (autoShowDropDownList)
+    {
+      ((CCombo)getControl()).setListVisible(true);
+    }
+  }
+
   public class FilteringAdapter implements KeyListener, FocusListener
   {
 
diff --git a/plugins/org.eclipse.emf.common.ui/src/org/eclipse/emf/common/ui/celleditor/ExtendedDialogCellEditor.java b/plugins/org.eclipse.emf.common.ui/src/org/eclipse/emf/common/ui/celleditor/ExtendedDialogCellEditor.java
index 2e733aa..afbd422 100644
--- a/plugins/org.eclipse.emf.common.ui/src/org/eclipse/emf/common/ui/celleditor/ExtendedDialogCellEditor.java
+++ b/plugins/org.eclipse.emf.common.ui/src/org/eclipse/emf/common/ui/celleditor/ExtendedDialogCellEditor.java
@@ -13,7 +13,12 @@
 
 import org.eclipse.jface.viewers.DialogCellEditor;
 import org.eclipse.jface.viewers.ILabelProvider;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.MouseAdapter;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.widgets.Button;
 import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
 
 
 /**
@@ -23,6 +28,8 @@
 {
   protected ILabelProvider labelProvider;
 
+  private Button button;
+
   public ExtendedDialogCellEditor(Composite composite, ILabelProvider labelProvider)
   {
     super(composite);
@@ -30,6 +37,31 @@
   }
 
   @Override
+  protected Control createContents(Composite cell)
+  {
+    final Control control = super.createContents(cell);
+    control.addMouseListener(new MouseAdapter()
+      {
+        @Override
+        public void mouseUp(MouseEvent event)
+        {
+          if (button != null)
+          {
+            button.notifyListeners(SWT.Selection, null);
+          }
+        }
+      });
+    return control;
+  }
+
+  @Override
+  protected Button createButton(Composite parent)
+  {
+    button = super.createButton(parent);
+    return button;
+  }
+
+  @Override
   protected void updateContents(Object object)
   {
     if (getDefaultLabel() != null && labelProvider != null)
diff --git a/plugins/org.eclipse.emf.common.ui/src/org/eclipse/emf/common/ui/viewer/ColumnResizer.java b/plugins/org.eclipse.emf.common.ui/src/org/eclipse/emf/common/ui/viewer/ColumnResizer.java
new file mode 100644
index 0000000..e0965c3
--- /dev/null
+++ b/plugins/org.eclipse.emf.common.ui/src/org/eclipse/emf/common/ui/viewer/ColumnResizer.java
@@ -0,0 +1,381 @@
+/**
+ * Copyright (c) 2017 Eclipse contributors and others.
+ * All rights reserved.   This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.eclipse.emf.common.ui.viewer;
+
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import org.eclipse.swt.events.ControlAdapter;
+import org.eclipse.swt.events.ControlEvent;
+import org.eclipse.swt.events.ControlListener;
+import org.eclipse.swt.events.DisposeEvent;
+import org.eclipse.swt.events.DisposeListener;
+import org.eclipse.swt.events.TreeEvent;
+import org.eclipse.swt.events.TreeListener;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Item;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableColumn;
+import org.eclipse.swt.widgets.Tree;
+import org.eclipse.swt.widgets.TreeColumn;
+
+
+/**
+ * This utility class provides {@link #addColumnResizer(Tree)} and {@link #addColumnResizer(Table)} to create a {@link ColumnResizer.Handler} that will pack all columns to their minimal size
+ * and will respond to {@link ControlListener#controlResized(ControlEvent) control resized} events to update the column sizes automatically.
+ * If needed, the last column will be expanded beyond its minimal packed size to make it large enough such that all Tree or Table columns exactly fit the {@link Composite#getClientArea() client area}.
+ * When the contents of the {@link Tree} or {@link Table} changes, the Handler can be instructed to {@link ColumnResizer.Handler#resizeColumns() resize} the columns.
+ * 
+ * @since 2.14
+ */
+public final class ColumnResizer
+{
+  private ColumnResizer()
+  {
+    throw new RuntimeException("No instances");
+  }
+
+  /**
+   * A handler created by {@link ColumnResizer#addColumnResizer(Tree)} or {@link ColumnResizer#addColumnResizer(Table)}.
+   * that provides the ability to manually {@link #resizeColumns() resize} the columns to their minimal packed size when the contents of the {@link Tree} or {@link Table} changes.
+   * If needed, the last column will be expanded beyond its minimal packed size to make it large enough such that all Tree or Table columns exactly fit the {@link Composite#getClientArea() client area}.
+   * The handler itself will respond to {@link ControlListener#controlResized(ControlEvent) control resized} events to update the column sizes automatically.
+   */
+  public static abstract class Handler
+  {
+    private Handler()
+    {
+    }
+
+    /**
+     * Resize all columns to their minimal packed size.
+     * This should be called when the contents of the {@link Tree} or {@link Table} changes.
+     */
+    public abstract void resizeColumns();
+
+    /**
+     * This removes this handler from the {@link Tree} or {@link Table} to which it was added.
+     */
+    public abstract void dispose();
+  }
+
+  /**
+   * Creates a handler for resizing all columns to their minimal packed size.
+   */
+  public static Handler addColumnResizer(Tree tree)
+  {
+    return new TreeColumnResizeHandler(tree);
+  }
+
+  /**
+   * Creates a handler for resizing all columns to their minimal packed size.
+   */
+  public static Handler addColumnResizer(Table table)
+  {
+    return new TableColumnResizeHandler(table);
+  }
+
+  private static class ParentHandler extends ControlAdapter implements DisposeListener, Runnable
+  {
+    private final Composite control;
+    
+    private final Composite parent;
+
+    private boolean dispatched;
+
+    public ParentHandler(Composite control)
+    {
+      this.control = control;
+      this.parent = control.getParent();
+      control.addDisposeListener(this);
+      parent.addControlListener(this);
+    }
+
+    public void run()
+    {
+      if (!parent.isDisposed() && dispatched)
+      {
+        dispatched = false;
+        parent.setRedraw(true);
+      }
+    }
+
+    @Override
+    public void controlResized(ControlEvent e)
+    {
+      if (!dispatched)
+      {
+        parent.setRedraw(false);
+        dispatched = true;
+        parent.getDisplay().asyncExec(this);
+      }
+    }
+
+    public void widgetDisposed(DisposeEvent e)
+    {
+      parent.removeControlListener(this);
+    }
+    
+    public void dispose()
+    {
+      run();
+      dispatched = false;
+      control.removeDisposeListener(this);
+      parent.removeControlListener(this);
+    }
+  }
+
+  private static abstract class ColumnResizerHandler<T extends Composite, C extends Item> extends Handler implements ControlListener
+  {
+    private final T control;
+
+    private final ParentHandler parentHandler;
+
+    private int clientWidth = -1;
+
+    private List<Integer> columnWidths = Collections.emptyList();
+
+    private boolean resizing;
+
+    public ColumnResizerHandler(T control)
+    {
+      this.control = control;
+      for (C column : getColumns())
+      {
+        disableResizeable(column);
+      }
+
+      parentHandler = new ParentHandler(control);
+      control.addControlListener(this);
+    }
+
+    public T getControl()
+    {
+      return control;
+    }
+
+    protected abstract boolean isEmpty();
+
+    protected abstract List<? extends C> getColumns();
+
+    protected abstract void disableResizeable(C column);
+
+    protected abstract int getWidth(C column);
+
+    protected abstract void setWidth(C column, int width);
+
+    protected abstract void pack(C column);
+
+    protected List<Integer> getColumnWidths()
+    {
+      List<? extends C> columns = getColumns();
+      List<Integer> result = new ArrayList<Integer>(columns.size());
+      for (C column : columns)
+      {
+        result.add(getWidth(column));
+      }
+      return result;
+    }
+
+    public void controlResized(ControlEvent controlEvent)
+    {
+      if (!resizing)
+      {
+        T control = getControl();
+        Rectangle clientArea = control.getClientArea();
+        int clientWidth = clientArea.width - clientArea.x;
+        List<Integer> columnWidths = getColumnWidths();
+
+        boolean inputChanged = controlEvent == null;
+        if (inputChanged || clientWidth != this.clientWidth || this.columnWidths.equals(columnWidths))
+        {
+          try
+          {
+            resizing = true;
+            control.setRedraw(false);
+
+            List<? extends C> columns = getColumns();
+            for (C column : columns)
+            {
+              pack(column);
+            }
+
+            List<Integer> packedColumnWidths = getColumnWidths();
+            int total = 0;
+            int limit = columns.size() - 1;
+            for (int i = 0; i < limit; ++i)
+            {
+              int width = packedColumnWidths.get(i) + 10;
+              total += width;
+              setWidth(columns.get(i), width);
+            }
+
+            int width = packedColumnWidths.get(limit);
+            if (total + width < clientWidth)
+            {
+              width = clientWidth - total;
+            }
+            setWidth(columns.get(limit), width);
+          }
+          finally
+          {
+            this.clientWidth = clientWidth;
+            this.columnWidths = getColumnWidths();
+            control.setRedraw(true);
+            parentHandler.run();
+            resizing = false;
+          }
+        }
+      }
+    }
+
+    public void controlMoved(ControlEvent e)
+    {
+    }
+
+    @Override
+    public void resizeColumns()
+    {
+      controlResized(null);
+    }
+
+    @Override
+    public void dispose()
+    {
+      parentHandler.dispose();
+      control.removeControlListener(this);
+    }
+  }
+
+  private static class TreeColumnResizeHandler extends ColumnResizerHandler<Tree, TreeColumn>
+  {
+    public TreeColumnResizeHandler(Tree tree)
+    {
+      super(tree);
+
+      class TreeStateListener implements TreeListener, Runnable
+      {
+        private boolean dispatched;
+
+        public void run()
+        {
+          dispatched = false;
+          if (!getControl().isDisposed())
+          {
+            resizeColumns();
+          }
+        }
+
+        private void dispatch()
+        {
+          if (!dispatched)
+          {
+            dispatched = true;
+            getControl().getDisplay().asyncExec(this);
+          }
+        }
+
+        public void treeCollapsed(TreeEvent e)
+        {
+          dispatch();
+        }
+
+        public void treeExpanded(TreeEvent e)
+        {
+          dispatch();
+        }
+      }
+
+      tree.addTreeListener(new TreeStateListener());
+    }
+
+    @Override
+    protected List<? extends TreeColumn> getColumns()
+    {
+      return Arrays.asList(getControl().getColumns());
+    }
+
+    @Override
+    protected void disableResizeable(TreeColumn column)
+    {
+      column.setResizable(false);
+    }
+
+    @Override
+    protected int getWidth(TreeColumn column)
+    {
+      return column.getWidth();
+    }
+
+    @Override
+    protected void setWidth(TreeColumn column, int width)
+    {
+      column.setWidth(width);
+    }
+
+    @Override
+    protected boolean isEmpty()
+    {
+      return getControl().getItemCount() != 0;
+    }
+
+    @Override
+    protected void pack(TreeColumn column)
+    {
+      column.pack();
+    }
+  }
+
+  private static class TableColumnResizeHandler extends ColumnResizerHandler<Table, TableColumn>
+  {
+    public TableColumnResizeHandler(Table table)
+    {
+      super(table);
+    }
+
+    @Override
+    protected List<? extends TableColumn> getColumns()
+    {
+      return Arrays.asList(getControl().getColumns());
+    }
+
+    @Override
+    protected void disableResizeable(TableColumn column)
+    {
+      column.setResizable(false);
+    }
+
+    @Override
+    protected int getWidth(TableColumn column)
+    {
+      return column.getWidth();
+    }
+
+    @Override
+    protected void setWidth(TableColumn column, int width)
+    {
+      column.setWidth(width);
+    }
+
+    @Override
+    protected boolean isEmpty()
+    {
+      return getControl().getItemCount() != 0;
+    }
+
+    @Override
+    protected void pack(TableColumn column)
+    {
+      column.pack();
+    }
+  }
+}
diff --git a/plugins/org.eclipse.emf.ecore.edit/META-INF/MANIFEST.MF b/plugins/org.eclipse.emf.ecore.edit/META-INF/MANIFEST.MF
index 12f4446..31a573d 100644
--- a/plugins/org.eclipse.emf.ecore.edit/META-INF/MANIFEST.MF
+++ b/plugins/org.eclipse.emf.ecore.edit/META-INF/MANIFEST.MF
@@ -2,13 +2,14 @@
 Bundle-ManifestVersion: 2
 Bundle-Name: %pluginName
 Bundle-SymbolicName: org.eclipse.emf.ecore.edit;singleton:=true
-Bundle-Version: 2.9.0.qualifier
+Bundle-Version: 2.10.0.qualifier
 Bundle-ClassPath: .
 Bundle-Activator: org.eclipse.emf.ecore.provider.EcoreEditPlugin$Implementation$Activator
 Bundle-Vendor: %providerName
 Bundle-Localization: plugin
 Bundle-RequiredExecutionEnvironment: J2SE-1.5
-Export-Package: org.eclipse.emf.ecore.provider
+Export-Package: org.eclipse.emf.ecore.provider,
+ org.eclipse.emf.ecore.provider.annotation
 Require-Bundle: org.eclipse.core.runtime;resolution:=optional;x-installation:=greedy,
  org.eclipse.emf.ecore;visibility:=reexport,
  org.eclipse.emf.edit;visibility:=reexport
diff --git a/plugins/org.eclipse.emf.ecore.edit/build.properties b/plugins/org.eclipse.emf.ecore.edit/build.properties
index 75f7adf..1722f9d 100644
--- a/plugins/org.eclipse.emf.ecore.edit/build.properties
+++ b/plugins/org.eclipse.emf.ecore.edit/build.properties
@@ -7,7 +7,8 @@
                icons/,\
                plugin.properties,\
                plugin.xml,\
-               META-INF/
+               META-INF/,\
+               schema/
 src.includes = about.html
 source.. = src/
 output.. = bin/
diff --git a/plugins/org.eclipse.emf.ecore.edit/plugin.properties b/plugins/org.eclipse.emf.ecore.edit/plugin.properties
index 359d155..a5f450f 100644
--- a/plugins/org.eclipse.emf.ecore.edit/plugin.properties
+++ b/plugins/org.eclipse.emf.ecore.edit/plugin.properties
@@ -191,3 +191,79 @@
 _UI_EGenericType_eRawType_description = The erased type denoted by this generic type
 _UI_EGenericType_eTypeParameter_description = The type parameter denoted by this generic type
 _UI_EGenericType_eClassifier_description = The classifier denoted by this generic type
+
+_UI_AnnotationItemProviderAdapterFactoryRegistry_extensionpoint = Annotation Item Provider Adapter Factory Registry
+
+_UI_Package_schemaLocation_feature = Schema Location 
+_UI_Package_schemaLocation_description = The URI where this Ecore model is located
+_UI_Package_settingDelegates_feature = Setting Delegates
+_UI_Package_settingDelegates_description = The URIs of setting delegates used on feature annotations
+_UI_Package_validationDelegates_feature = Validation Delegates
+_UI_Package_validationDelegates_description = The URIs of validation delegates used on classifier annotations
+_UI_Package_conversionDelegates_feature = Conversion Delegates
+_UI_Package_conversionDelegates_description = The URIs of the conversion delegates used on data type annotations
+_UI_Package_invocationDelegates_feature = Invocation Delegates
+_UI_Package_invocationDelegates_description = The URIs of invocation delegates used on operation annotations
+_UI_Classifier_constraints_feature = Constraints
+_UI_Classifier_constraints_description = The names of constraints validated by this classifier
+_UI_Operation_invariant_feature = Invariant
+_UI_Operation_invariant_description = Whether this operation is an invariant invoked by the validator
+
+
+_UI_Package_qualified_feature =  Qualified
+_UI_Package_qualified_description = Whether this package should use its namespace URI or should use the empty namespace
+_UI_Class_documentRoot_feature = Document Root
+_UI_Class_documentRoot_description = Whether this class represents the document root of this package
+_UI_Class_kind_feature = Kind
+_UI_Class_kind_description = The kind of content of this class
+_UI_DataType_baseType_feature = Base Type
+_UI_DataType_baseType_description = The base data type that this type restricts
+_UI_DataType_itemType_feature = Item Type
+_UI_DataType_itemType_description = The item type of this list data type
+_UI_DataType_memberTypes_feature = Member Types
+_UI_DataType_memberTypes_description = The member types of this union data type
+_UI_DataType_whiteSpace_feature = White Space
+_UI_DataType_whiteSpace_description = The kind of processing for the white space of the values of this data type
+_UI_DataType_enumeration_feature = Enumeration
+_UI_DataType_enumeration_description = The explicit list of permitted values for this data type
+_UI_DataType_pattern_feature = Pattern
+_UI_DataType_pattern_description = The list of XML Schema patterns all of which must match a literal value of this data type
+_UI_DataType_totalDigits_feature = Total Digits
+_UI_DataType_totalDigits_description = The total number of digits of a value of this data type
+_UI_DataType_fractionDigits_feature = Fraction Digits
+_UI_DataType_fractionDigits_description = The number of fraction digits of a value of this data type
+_UI_DataType_length_feature = Length
+_UI_DataType_length_description = The exact permitted length of the list or of the literal value of this data type
+_UI_DataType_minLength_feature = Min Length
+_UI_DataType_minLength_description = The minimum permitted length of the list or the literal value of this data type
+_UI_DataType_maxLength_feature = Max Length
+_UI_DataType_maxLength_description = The maximum permitted length of the list or the literal value of this data type
+_UI_DataType_minExclusive_feature = Min Exclusive
+_UI_DataType_minExclusive_description = The minimum permitted value of this data type, excluding this value 
+_UI_DataType_maxExclusive_feature = Max Exclusive
+_UI_DataType_maxExclusive_description = The maximum permitted value of this data type, excluding this value
+_UI_DataType_minInclusive_feature = Min Inclusive
+_UI_DataType_minInclusive_description = The minimum permitted value of this data type, including this value
+_UI_DataType_maxInclusive_feature = Max Inclusive
+_UI_DataType_maxInclusive_description = The maximum permitted value of this data type, including this value
+_UI_StructuralFeature_namespace_feature = Namespace
+_UI_StructuralFeature_namespace_description = The namespace of this feature in the XML serialization
+_UI_StructuralFeature_name_feature = Name
+_UI_StructuralFeature_name_description =  The name of this feature in the XML serialization
+_UI_StructuralFeature_kind_feature = Kind
+_UI_StructuralFeature_kind_description = The kind of feature in the XML serialization
+_UI_StructuralFeature_wildcards_feature = Wildcards
+_UI_StructuralFeature_wildcards_description = The namespaces allowed by this feature in the XML serialization
+_UI_StructuralFeature_processing_feature = Processing
+_UI_StructuralFeature_processing_description = The type of wildcard processing for the feature during XML deserialization
+_UI_StructuralFeature_group_feature = Group
+_UI_StructuralFeature_group_description = The feature in which this feature is grouped
+_UI_StructuralFeature_affiliation_feature = Affiliation
+_UI_StructuralFeature_affiliation_description = The feature which which this feature is affiliated
+_UI_Classifier_name_feature = Name
+_UI_Classifier_name_description = The name of this type in an xsi:type attribute in the XML serialization; a name containing a '':'' is anonymous and can't be referred to by name
+
+_UI_ChangeExtendedMetaData_text = Change Extend Meta Data
+_UI_ChangeExtendedMetaData_description = Change the extended meta data
+
+_UI_Misc_property_category = Misc
diff --git a/plugins/org.eclipse.emf.ecore.edit/plugin.xml b/plugins/org.eclipse.emf.ecore.edit/plugin.xml
index 485b7ee..a19eaf3 100644
--- a/plugins/org.eclipse.emf.ecore.edit/plugin.xml
+++ b/plugins/org.eclipse.emf.ecore.edit/plugin.xml
@@ -1,6 +1,8 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <?eclipse version="3.0"?>
 <plugin>
+   <extension-point id="annotation_item_provider_adapter_factory" name="%_UI_AnnotationItemProviderAdapterFactoryRegistry_extensionpoint" schema="schema/annotation_item_provider_adapter_factory.exsd"/>
+
    <extension point="org.eclipse.emf.edit.itemProviderAdapterFactories">
       <factory
             uri="http://www.eclipse.org/emf/2002/Ecore"
@@ -12,4 +14,17 @@
                org.eclipse.emf.edit.provider.IItemLabelProvider
                org.eclipse.emf.edit.provider.IItemPropertySource"/>
    </extension>
+
+   <extension
+         point="org.eclipse.emf.ecore.edit.annotation_item_provider_adapter_factory">
+      <factory
+            uri="http://www.eclipse.org/emf/2002/Ecore"
+            class="org.eclipse.emf.ecore.provider.annotation.EcoreAnnotationItemProviderAdapterFactory">
+      </factory>
+      <factory
+            uri="http:///org/eclipse/emf/ecore/util/ExtendedMetaData"
+            class="org.eclipse.emf.ecore.provider.annotation.ExtendedMetaDataAnnotationItemProviderAdapterFactory">
+      </factory>
+   </extension>
+
 </plugin>
diff --git a/plugins/org.eclipse.emf.ecore.edit/schema/annotation_item_provider_adapter_factory.exsd b/plugins/org.eclipse.emf.ecore.edit/schema/annotation_item_provider_adapter_factory.exsd
new file mode 100644
index 0000000..0bbc174
--- /dev/null
+++ b/plugins/org.eclipse.emf.ecore.edit/schema/annotation_item_provider_adapter_factory.exsd
@@ -0,0 +1,124 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<!-- Schema file written by PDE -->
+<schema targetNamespace="org.eclipse.emf.ecore.edit" xmlns="http://www.w3.org/2001/XMLSchema">
+<annotation>
+      <appInfo>
+         <meta.schema plugin="org.eclipse.emf.ecore.edit" id="annotation_item_provider_adapter_factory" name="Annotation Item Provider Adapter Factory"/>
+      </appInfo>
+      <documentation>
+         This extension point is used to define an annotation item provider adapter factory for creating item providers for annotations with the specified annotation source as well as item providers for their details. The global EMF annotation item provider adapter factory registry, &lt;samp&gt;EAnnotationItemProviderAdapterFactory.Registry.INSTANCE&lt;/samp&gt;, is used to record the registration.
+      </documentation>
+   </annotation>
+
+   <element name="extension">
+      <annotation>
+         <appInfo>
+            <meta.element />
+         </appInfo>
+      </annotation>
+      <complexType>
+         <sequence>
+            <element ref="factory" minOccurs="1" maxOccurs="unbounded"/>
+         </sequence>
+         <attribute name="point" type="string" use="required">
+            <annotation>
+               <documentation>
+                  A fully qualified identifier of the target extension point.
+               </documentation>
+            </annotation>
+         </attribute>
+         <attribute name="id" type="string">
+            <annotation>
+               <documentation>
+                  An optional identifier of the extension instance.
+               </documentation>
+            </annotation>
+         </attribute>
+         <attribute name="name" type="string">
+            <annotation>
+               <documentation>
+                  An optional name of the extension instance.
+               </documentation>
+            </annotation>
+         </attribute>
+      </complexType>
+   </element>
+
+   <element name="factory">
+      <annotation>
+         <appInfo>
+            <meta.element labelAttribute="id"/>
+         </appInfo>
+      </annotation>
+      <complexType>
+         <attribute name="uri" type="string" use="required">
+            <annotation>
+               <documentation>
+                  A URI identifying the annotation source of the annotation to be extended
+               </documentation>
+            </annotation>
+         </attribute>
+         <attribute name="class" type="string" use="required">
+            <annotation>
+               <documentation>
+                  The fully qualified name of a Java class extending &lt;samp&gt;org.eclipse.emf.ecore.provider.annotation.EAnnotationItemProviderAdapterFactory&lt;/samp&gt;.
+               </documentation>
+               <appInfo>
+                  <meta.attribute kind="java" basedOn="org.eclipse.emf.ecore.provider.annotation.EAnnotationItemProviderAdapterFactory:"/>
+               </appInfo>
+            </annotation>
+         </attribute>
+      </complexType>
+   </element>
+
+   <annotation>
+      <appInfo>
+         <meta.section type="since"/>
+      </appInfo>
+      <documentation>
+         2.14.0
+      </documentation>
+   </annotation>
+
+   <annotation>
+      <appInfo>
+         <meta.section type="examples"/>
+      </appInfo>
+      <documentation>
+         Following is an example of how a annotation item provider adapter factory can be registered: 
+&lt;pre&gt;
+  &lt;extension point=&quot;org.eclipse.emf.ecore.annotation_item_provider_adapter_factory&quot;&gt;
+    &lt;factory uri=&quot;http://www.eclipse.org/emf/2002/Ecore&quot; class=&quot;org.eclipse.emf.ecore.provider.annotation.EcoreAnnotationItemProviderAdapterFactory&quot;/&gt; 
+  &lt;/extension&gt;
+&lt;/pre&gt;
+      </documentation>
+   </annotation>
+
+   <annotation>
+      <appInfo>
+         <meta.section type="apiInfo"/>
+      </appInfo>
+      <documentation>
+         The value of the class attribute must represent a class that extends &lt;samp&gt;org.eclipse.emf.ecore.provider.annotation.EAnnotationItemProviderAdapterFactory&lt;/samp&gt; and has a no argument contructor.
+&lt;p&gt;
+An annotation item provider adapter factory can be also registered from the source code with the &lt;samp&gt;EAnnotationItemProviderAdapterFactory&lt;/samp&gt; as follows:
+&lt;/p&gt;
+&lt;pre&gt;
+  EAnnotationItemProviderAdapterFactory.Registry.INSTANCE.put(&quot;http://www.eclipse.org/emf/2002/Ecore&quot;, new EcoreAnnotationItemProviderAdapterFactory());
+&lt;/pre&gt;
+      </documentation>
+   </annotation>
+
+
+   <annotation>
+      <appInfo>
+         <meta.section type="copyright"/>
+      </appInfo>
+      <documentation>
+         Copyright (c) 2017 Eclipse contributors and others.&lt;br&gt;
+All rights reserved. This program and the accompanying materials are made available under the terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at &lt;a 
+href=&quot;http://www.eclipse.org/legal/epl-v10.html&quot;&gt;http://www.eclipse.org/legal/epl-v10.html&lt;/a&gt;
+      </documentation>
+   </annotation>
+
+</schema>
diff --git a/plugins/org.eclipse.emf.ecore.edit/src/org/eclipse/emf/ecore/provider/EAnnotationItemProvider.java b/plugins/org.eclipse.emf.ecore.edit/src/org/eclipse/emf/ecore/provider/EAnnotationItemProvider.java
index bf48f98..4572f1d 100644
--- a/plugins/org.eclipse.emf.ecore.edit/src/org/eclipse/emf/ecore/provider/EAnnotationItemProvider.java
+++ b/plugins/org.eclipse.emf.ecore.edit/src/org/eclipse/emf/ecore/provider/EAnnotationItemProvider.java
@@ -12,34 +12,55 @@
 
 
 import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
 import java.util.List;
+import java.util.Map;
 
 import org.eclipse.emf.common.notify.AdapterFactory;
 import org.eclipse.emf.common.notify.Notification;
+import org.eclipse.emf.common.util.BasicDiagnostic;
+import org.eclipse.emf.common.util.Diagnostic;
+import org.eclipse.emf.common.util.UniqueEList;
 import org.eclipse.emf.ecore.EAnnotation;
+import org.eclipse.emf.ecore.EAnnotationValidator;
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EDataType;
+import org.eclipse.emf.ecore.EObject;
 import org.eclipse.emf.ecore.EStructuralFeature;
 import org.eclipse.emf.ecore.EcoreFactory;
 import org.eclipse.emf.ecore.EcorePackage;
+import org.eclipse.emf.ecore.provider.annotation.EAnnotationItemProviderAdapterFactory;
+import org.eclipse.emf.ecore.provider.annotation.EAnnotationItemProviderAdapterFactory.Group;
+import org.eclipse.emf.ecore.provider.annotation.EcoreAnnotationItemProviderAdapterFactory;
+import org.eclipse.emf.ecore.util.BasicEAnnotationValidator;
+import org.eclipse.emf.ecore.util.EcoreUtil;
+import org.eclipse.emf.ecore.util.EcoreValidator;
 import org.eclipse.emf.edit.provider.ComposeableAdapterFactory;
+import org.eclipse.emf.edit.provider.IItemLabelProvider;
 import org.eclipse.emf.edit.provider.IItemPropertyDescriptor;
+import org.eclipse.emf.edit.provider.IItemPropertySource;
 import org.eclipse.emf.edit.provider.ItemPropertyDescriptor;
-
 import org.eclipse.emf.edit.provider.ViewerNotification;
 
+
 /**
  * This is the item provider adapter for a {@link org.eclipse.emf.ecore.EAnnotation} object.
  * <!-- begin-user-doc -->
+ * <p>
+ * This implementation is {@link EAnnotationItemProviderAdapterFactory}-aware using {@link #getEAnnotationItemProviderAdapterFactory()} to drive specialized behavior.
+ * I.e., it behaves differently when created by {@link EcoreItemProviderAdapterFactory} versus when created by {@link EAnnotationItemProviderAdapterFactory}.
+ * </p>
  * <!-- end-user-doc -->
  * @generated
  */
-public class EAnnotationItemProvider
-  extends EModelElementItemProvider
+public class EAnnotationItemProvider extends EModelElementItemProvider
 {
   /**
    * This constructs an instance from a factory and a notifier.
    * <!-- begin-user-doc -->
    * <!-- end-user-doc -->
-   * @generated
    */
   public EAnnotationItemProvider(AdapterFactory adapterFactory)
   {
@@ -47,13 +68,45 @@
   }
 
   /**
+   * Gets the root factory, which must be a {@link ComposeableAdapterFactory}.
+   *
+   * @since 2.14
+   */
+  @Override
+  protected ComposeableAdapterFactory getRootAdapterFactory()
+  {
+    return ((ComposeableAdapterFactory)adapterFactory).getRootAdapterFactory();
+  }
+
+  /**
+   * Returns the {@link EAnnotationItemProviderAdapterFactory} if the adapter factory is of that type, <code>null</code> otherwise.
+   * @return the annotation item provider adapter factory or <code>null</code>
+   * @since 2.14
+   */
+  protected EAnnotationItemProviderAdapterFactory getEAnnotationItemProviderAdapterFactory()
+  {
+    return adapterFactory instanceof EAnnotationItemProviderAdapterFactory ? (EAnnotationItemProviderAdapterFactory)adapterFactory : null;
+  }
+
+  /**
+   * Returns the {@link EAnnotationItemProviderAdapterFactory#getAssistant() assistant} of the {@link #getEAnnotationItemProviderAdapterFactory() annotation item provider adapter factory}, if available.
+   * @return the assistant or <code>null</code>.
+   * @since 2.14
+   */
+  protected BasicEAnnotationValidator.Assistant getAssistant()
+  {
+    EAnnotationItemProviderAdapterFactory eAnnotationItemProviderAdapterFactory = getEAnnotationItemProviderAdapterFactory();
+    return eAnnotationItemProviderAdapterFactory == null ? null : eAnnotationItemProviderAdapterFactory.getAssistant();
+  }
+
+  /**
    * This returns the property descriptors for the adapted class.
    * <!-- begin-user-doc -->
+   * @since 2.14
    * <!-- end-user-doc -->
    * @generated
    */
-  @Override
-  public List<IItemPropertyDescriptor> getPropertyDescriptors(Object object)
+  protected List<IItemPropertyDescriptor> getPropertyDescriptorsGen(Object object)
   {
     if (itemPropertyDescriptors == null)
     {
@@ -66,54 +119,339 @@
   }
 
   /**
+   * {@inheritDoc}
+   * <p>
+   * This implementation is specialized to clear the cached {@link #itemPropertyDescriptors descriptors} if this adapter was created by an {@link EAnnotationItemProviderAdapterFactory}.
+   * <p>
+   */
+  @Override
+  public List<IItemPropertyDescriptor> getPropertyDescriptors(Object object)
+  {
+    if (getEAnnotationItemProviderAdapterFactory() != null)
+    {
+      itemPropertyDescriptors = null;
+    }
+
+    List<IItemPropertyDescriptor> propertyDescriptors = getPropertyDescriptorsGen(object);
+    return propertyDescriptors;
+  }
+
+  /**
    * This adds a property descriptor for the Source feature.
    * <!-- begin-user-doc -->
+   * This implementation is specialized to create a {@link SourcePropertyDescriptor}.
    * <!-- end-user-doc -->
    * @generated NOT
    */
   protected void addSourcePropertyDescriptor(Object object)
   {
-    itemPropertyDescriptors.add
-      (new ItemPropertyDescriptor
-        (((ComposeableAdapterFactory)adapterFactory).getRootAdapterFactory(),
-         getResourceLocator(),
-         getString("_UI_EAnnotation_source_feature"),
-         getString("_UI_EAnnotation_source_description"),
-         EcorePackage.Literals.EANNOTATION__SOURCE,
-         true,
-         ItemPropertyDescriptor.GENERIC_VALUE_IMAGE,
-         null,
-         null)
-       {
-         @Override
-        public void setPropertyValue(Object object, Object value)
-         {
-           super.setPropertyValue(object, stripToNull((String)value));
-         }
-       });
+    itemPropertyDescriptors.add(new SourcePropertyDescriptor());
+  }
+
+  /**
+   * A specialized property descriptor for the {@link EAnnotation#getSource() annotation source} feature.
+   * <p>
+   * This implementation that is {@link EAnnotationItemProviderAdapterFactory}-aware,
+   * using its {@link EAnnotationItemProviderAdapterFactory#getAssistant() assistant} when available.
+   * It specializes {@link #createPropertyValueWrapper(Object, Object) property value wrapper creation} to provide assistant-driven nested property descriptors.
+   * </p>
+   *
+   * @since 2.14
+   */
+  protected class SourcePropertyDescriptor extends ItemPropertyDescriptor
+  {
+    public SourcePropertyDescriptor()
+    {
+      super(
+        getRootAdapterFactory(),
+        getResourceLocator(),
+        getString("_UI_EAnnotation_source_feature"),
+        getString("_UI_EAnnotation_source_description"),
+        EcorePackage.Literals.EANNOTATION__SOURCE,
+        true,
+        false,
+        true,
+        ItemPropertyDescriptor.GENERIC_VALUE_IMAGE,
+        null,
+        null);
+    }
+
+    /**
+     * Creates a property value wrapper for the given object's property value.
+     * <p>
+     * This implementation creates a hierarchy of property descriptors if the {@link #getAssistant() assistant} is available,
+     * if the assistant considers the annotation {@link org.eclipse.emf.ecore.util.BasicEAnnotationValidator.Assistant#isValidLocation(EAnnotation) valid at this location},
+     * and if the assistant returns {@link org.eclipse.emf.ecore.util.BasicEAnnotationValidator.Assistant#getPropertyClasses(org.eclipse.emf.ecore.EModelElement) one or more modeled annotation classes}.
+     * In that case, it {@link org.eclipse.emf.ecore.util.BasicEAnnotationValidator.Assistant#createInstance(EClass, EAnnotation) creates} the modeled object of each class,
+     * {@link EAnnotationItemProviderAdapterFactory#isShowInstances(EAnnotation) optionally including} it in the tree,
+     * and if the property descriptors are {@link org.eclipse.emf.ecore.provider.annotation.EAnnotationItemProviderAdapterFactory.DecategorizingItemPropertyDescritorDecorator#getCategory() categorized},
+     * it creates an additional tree nesting per category.
+     * Otherwise it simply creates simply delegates to <code>super</code>.
+     * <p>
+     * @param object the object.
+     * @param propertyValue the property value of that object.
+     */
+    @Override
+    protected Object createPropertyValueWrapper(Object object, Object propertyValue)
+    {
+      BasicEAnnotationValidator.Assistant assistant = getAssistant();
+      if (assistant != null)
+      {
+        final EAnnotation eAnnotation = (EAnnotation)object;
+        if (assistant.isValidLocation(eAnnotation))
+        {
+          List<EClass> propertyClasses = assistant.getPropertyClasses(eAnnotation.getEModelElement());
+          if (!propertyClasses.isEmpty())
+          {
+            EcoreAnnotationItemProviderAdapterFactory.Group group = new EcoreAnnotationItemProviderAdapterFactory.Group(propertyValue);
+            Map<String, Group> categories = new HashMap<String, Group>();
+            EAnnotationItemProviderAdapterFactory eAnnotationItemProviderAdapterFactory = getEAnnotationItemProviderAdapterFactory();
+            boolean showInstances = eAnnotationItemProviderAdapterFactory.isShowInstances(eAnnotation);
+            boolean onlyMisc = true;
+            for (EClass propertyClass : propertyClasses)
+            {
+              EObject instance = assistant.createInstance(propertyClass, eAnnotation);
+              Group targetGroup = group;
+              if (showInstances)
+              {
+                Group classGroup = new Group(instance);
+                String groupName = eAnnotationItemProviderAdapterFactory.getResourceLocator().getString("_UI_" + instance.eClass().getName() + "_type");
+                GroupPropertyDescriptor groupPropertyDescriptor = new GroupPropertyDescriptor(groupName, groupName, classGroup);
+                group.add(groupPropertyDescriptor);
+                targetGroup = classGroup;
+                categories.clear();
+                onlyMisc = true;
+              }
+
+              List<IItemPropertyDescriptor> propertyDescriptors = eAnnotationItemProviderAdapterFactory.getPropertyDescriptors(
+                instance,
+                eAnnotation,
+                eAnnotationItemProviderAdapterFactory.getResourceLocator());
+              for (IItemPropertyDescriptor propertyDescriptor : propertyDescriptors)
+              {
+                String category = null;
+                if (propertyDescriptor instanceof EAnnotationItemProviderAdapterFactory.DecategorizingItemPropertyDescritorDecorator)
+                {
+                  category = ((EAnnotationItemProviderAdapterFactory.DecategorizingItemPropertyDescritorDecorator)propertyDescriptor).getCategory();
+                }
+
+                Group categoryGroup = categories.get(category);
+                if (categoryGroup == null)
+                {
+                  categoryGroup = new Group(category);
+                  categories.put(category, categoryGroup);
+                  if (category == null)
+                  {
+                    category = EcoreEditPlugin.INSTANCE.getString("_UI_Misc_property_category");
+                  }
+                  else
+                  {
+                    onlyMisc = false;
+                  }
+
+                  targetGroup.add(new GroupPropertyDescriptor(category, category, categoryGroup));
+                }
+
+                categoryGroup.add(propertyDescriptor);
+              }
+
+              if (showInstances && onlyMisc)
+              {
+                List<IItemPropertyDescriptor> groupPropertyDescriptors = targetGroup.getPropertyDescriptors();
+                groupPropertyDescriptors.clear();
+                groupPropertyDescriptors.addAll(categories.values().iterator().next().getPropertyDescriptors());
+              }
+            }
+
+            if (!showInstances && onlyMisc)
+            {
+              List<IItemPropertyDescriptor> groupPropertyDescriptors = group.getPropertyDescriptors();
+              groupPropertyDescriptors.clear();
+              groupPropertyDescriptors.addAll(categories.values().iterator().next().getPropertyDescriptors());
+            }
+
+            return group;
+          }
+        }
+      }
+
+      return super.createPropertyValueWrapper(object, propertyValue);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setPropertyValue(Object object, Object value)
+    {
+      EAnnotation eAnnotation = (EAnnotation)object;
+      String source = eAnnotation.getSource();
+      String strippedValue = stripToNull((String)value);
+      if (strippedValue == null ? source != null : !strippedValue.equals(source))
+      {
+        super.setPropertyValue(object, strippedValue);
+      }
+    }
+
+    /**
+     * {@inheritDoc}
+     * <p>
+     * This implementation collects all the existing {@link EAnnotation#getSource() annotation sources} in the containing model,
+     * adds to that the annotation source of any {@link org.eclipse.emf.ecore.EAnnotationValidator.Registry registered} annotation validator
+     * that returns <code>true</code> for {@link EAnnotationValidator#isValidLocation(EAnnotation)},
+     * removing the annotation source for any annotation validator that returns <code>false</code>.
+     * </p>
+     */
+    @Override
+    public Collection<?> getChoiceOfValues(Object object)
+    {
+      EAnnotation eAnnotation = (EAnnotation)object;
+      List<Object> result = new UniqueEList<Object>();
+
+      // Gather up all well-formed annotation sources already present in the tree on other annotations.
+      for (Iterator<EObject> i = EcoreUtil.getRootContainer(eAnnotation).eAllContents(); i.hasNext();)
+      {
+        EObject eObject = i.next();
+        if (eObject instanceof EAnnotation)
+        {
+          EAnnotation otherEAnnotation = (EAnnotation)eObject;
+          String otherSource = otherEAnnotation.getSource();
+          if (otherSource != null && EcoreValidator.INSTANCE.validateEAnnotation_WellFormedSourceURI(otherEAnnotation, null, null))
+          {
+            result.add(otherSource);
+          }
+        }
+      }
+
+      for (String annotationSource : EAnnotationValidator.Registry.INSTANCE.keySet())
+      {
+        EAnnotationValidator eAnnotationValidator = EAnnotationValidator.Registry.INSTANCE.getEAnnotationValidator(annotationSource);
+        if (eAnnotationValidator.isValidLocation(eAnnotation))
+        {
+          result.add(annotationSource);
+        }
+        else
+        {
+          result.remove(annotationSource);
+        }
+      }
+
+      String source = eAnnotation.getSource();
+      if (source != null)
+      {
+        result.add(source);
+      }
+
+      return result;
+    }
+
+    /**
+     * {@inheritDoc}
+     * <p>
+     * This implementation is specialized to always return <code>true</code>.
+     * </p>
+     */
+    @Override
+    public boolean isChoiceArbitrary(Object object)
+    {
+      return true;
+    }
+
+    /**
+     * {@inheritDoc}
+     * <p>
+     * This is specialized to do additional validation
+     * checking to ensure that the source URI is {@link EcoreValidator#validateEAnnotation_WellFormedSourceURI(EAnnotation, org.eclipse.emf.common.util.DiagnosticChain, Map) well-formed}.
+     * </p>
+     */
+    @Override
+    public ValueHandler getValueHandler(Object object)
+    {
+      return new DataTypeValueHandler((EDataType)feature.getEType())
+        {
+          @Override
+          protected Diagnostic validate(EDataType eDataType, Object instance)
+          {
+            EAnnotation eAnnotation = EcoreFactory.eINSTANCE.createEAnnotation();
+            eAnnotation.setSource((String)instance);
+            BasicDiagnostic diagnostic = new BasicDiagnostic();
+            EcoreValidator.INSTANCE.validateEAnnotation_WellFormedSourceURI(eAnnotation, diagnostic, null);
+            return diagnostic;
+          }
+        };
+    }
   }
 
   /**
    * This adds a property descriptor for the References feature.
    * <!-- begin-user-doc -->
+   * This implementation is specialized to use the {@link #getAssistant() assistant} when available.
+   * If the assistant indicates that {@link org.eclipse.emf.ecore.util.BasicEAnnotationValidator.Assistant#isReferencesSupported(EAnnotation) references aren't supported}
+   * and the {@link EAnnotation#getReferences() references} are empty,
+   * the property descriptor is not added.
+   * Otherwise an instance of {@link ReferencesPropertyDescriptor} is created.
+   * @see ReferencesPropertyDescriptor
    * <!-- end-user-doc -->
-   * @generated
+   * @generated NOT
    */
   protected void addReferencesPropertyDescriptor(Object object)
   {
-    itemPropertyDescriptors.add
-      (createItemPropertyDescriptor
-        (((ComposeableAdapterFactory)adapterFactory).getRootAdapterFactory(),
-         getResourceLocator(),
-         getString("_UI_EAnnotation_references_feature"),
-         getString("_UI_EAnnotation_references_description"),
-         EcorePackage.Literals.EANNOTATION__REFERENCES,
-         true,
-         false,
-         true,
-         null,
-         null,
-         null));
+    BasicEAnnotationValidator.Assistant assistant = getAssistant();
+    if (assistant != null)
+    {
+      EAnnotation eAnnotation = (EAnnotation)object;
+      if (!assistant.isReferencesSupported(eAnnotation) && eAnnotation.getReferences().isEmpty())
+      {
+        return;
+      }
+    }
+    itemPropertyDescriptors.add(new ReferencesPropertyDescriptor());
+  }
+
+  /**
+   * A specialized property descriptor for the {@link EAnnotation#getReferences() annotation references} feature.
+   * Specialized {@link EAnnotationItemProvider annotation item providers}
+   * created by an {@link EAnnotationItemProviderAdapterFactory annotation item provider adapter factory}
+   * can override the {@link #getChoiceOfValues(Object) value choices} to provide more restricted choices.
+   * But they won't generally need to do that because this implementation delegates to the {@link EAnnotationItemProvider#getAssistant() assistant}.
+   *
+   * @since 2.14
+   */
+  protected class ReferencesPropertyDescriptor extends ItemPropertyDescriptor
+  {
+    public ReferencesPropertyDescriptor()
+    {
+      super(
+        getRootAdapterFactory(),
+        getResourceLocator(),
+        getString("_UI_EAnnotation_references_feature"),
+        getString("_UI_EAnnotation_references_description"),
+        EcorePackage.Literals.EANNOTATION__REFERENCES,
+        true,
+        false,
+        true,
+        null,
+        null,
+        null);
+    }
+
+    /**
+     * {@inheritDoc}
+     * <p>
+     * This implementation is specialized to delegate to the {@link org.eclipse.emf.ecore.util.BasicEAnnotationValidator.Assistant#getValidReferences(EAnnotation, Collection) assistant}.
+     * </p>
+     */
+    @Override
+    public Collection<?> getChoiceOfValues(Object object)
+    {
+      Collection<?> result = super.getChoiceOfValues(object);
+      BasicEAnnotationValidator.Assistant assistant = getAssistant();
+      if (assistant != null)
+      {
+        result = assistant.getValidReferences((EAnnotation)object, result);
+      }
+      return result;
+    }
   }
 
   /**
@@ -137,17 +475,45 @@
   }
 
   /**
-   * <!-- begin-user-doc -->
-   * <!-- end-user-doc -->
-   * @generated
+   * This implementation is specialized to use the {@link org.eclipse.emf.ecore.util.BasicEAnnotationValidator.Assistant assistant} if available
+   * to avoid adding the child if it would produce an invalid annotations.
+   * @see org.eclipse.emf.ecore.util.BasicEAnnotationValidator.Assistant#getValidAnnotations(EAnnotation, Collection) Assistant.getValidAnnotations(EAnnotation, Collection)
+   * @see org.eclipse.emf.ecore.util.BasicEAnnotationValidator.Assistant#getValidContents(EAnnotation, Collection) Assistant.getValidContents(EAnnotation, Collection)
+   * @generated NOT
    */
   @Override
   protected EStructuralFeature getChildFeature(Object object, Object child)
   {
-    // Check the type of the specified child object and return the proper feature to use for
-    // adding (see {@link AddCommand}) it as a child.
-
-    return super.getChildFeature(object, child);
+    EStructuralFeature childFeature = super.getChildFeature(object, child);
+    BasicEAnnotationValidator.Assistant assistant = getAssistant();
+    if (assistant != null)
+    {
+      EAnnotation eAnnotation = (EAnnotation)object;
+      if (child instanceof EAnnotation)
+      {
+        EAnnotation nestedEAnnotation = (EAnnotation)child;
+        if (assistant.getValidAnnotations(eAnnotation, Collections.singletonList(nestedEAnnotation)).contains(nestedEAnnotation))
+        {
+          return EcorePackage.Literals.EMODEL_ELEMENT__EANNOTATIONS;
+        }
+        else if (childFeature == EcorePackage.Literals.EMODEL_ELEMENT__EANNOTATIONS)
+        {
+          return null;
+        }
+      }
+      if (child instanceof EObject)
+      {
+        if (assistant.getValidContents(eAnnotation, Collections.singletonList((EObject)child)).contains(child))
+        {
+          return EcorePackage.Literals.EANNOTATION__CONTENTS;
+        }
+        else if (childFeature == EcorePackage.Literals.EANNOTATION__CONTENTS)
+        {
+          return null;
+        }
+      }
+    }
+    return childFeature;
   }
 
   /**
@@ -172,17 +538,18 @@
   public String getText(Object object)
   {
     EAnnotation eAnnotation = (EAnnotation)object;
-    StringBuffer result = new StringBuffer();
-    if (eAnnotation.getSource() != null)
+    StringBuilder result = new StringBuilder();
+    String source = eAnnotation.getSource();
+    if (source != null)
     {
-      int index = getParent(eAnnotation) instanceof EAnnotation ? -1 : eAnnotation.getSource().lastIndexOf("/");
+      int index = getParent(eAnnotation) instanceof EAnnotation ? -1 : source.lastIndexOf("/");
       if (index == -1)
       {
-        result.append(eAnnotation.getSource());
+        result.append(source);
       }
       else
       {
-        result.append(eAnnotation.getSource().substring(index + 1));
+        result.append(source.substring(index + 1));
       }
     }
     return result.toString();
@@ -223,12 +590,153 @@
   @Override
   protected void collectNewChildDescriptors(Collection<Object> newChildDescriptors, Object object)
   {
-    // super.collectNewChildDescriptors(newChildDescriptors, object);
+    BasicEAnnotationValidator.Assistant assistant = getAssistant();
+    if (assistant != null)
+    {
+      EAnnotation eAnnotation = (EAnnotation)object;
+      Collection<? extends EObject> validContents = assistant.getValidContents(eAnnotation, Collections.<EObject> emptyList());
+      for (EObject validContent : validContents)
+      {
+        newChildDescriptors.add(createChildParameter(EcorePackage.Literals.EANNOTATION__CONTENTS, validContent));
+      }
+      Collection<? extends EAnnotation> validAnnotations = assistant.getValidAnnotations(eAnnotation, Collections.<EAnnotation> emptyList());
+      for (EAnnotation validAnnotation : validAnnotations)
+      {
+        newChildDescriptors.add(createChildParameter(EcorePackage.Literals.EMODEL_ELEMENT__EANNOTATIONS, validAnnotation));
+      }
+    }
 
-    newChildDescriptors.add
-    (createChildParameter
-      (EcorePackage.Literals.EANNOTATION__DETAILS,
-       EcoreFactory.eINSTANCE.create(EcorePackage.Literals.ESTRING_TO_STRING_MAP_ENTRY)));
+    newChildDescriptors.add(createChildParameter(EcorePackage.Literals.EANNOTATION__DETAILS, EcoreFactory.eINSTANCE.create(EcorePackage.Literals.ESTRING_TO_STRING_MAP_ENTRY)));
   }
 
+  @Override
+  public String getCreateChildText(Object owner, Object feature, Object child, Collection<?> selection)
+  {
+    String result = super.getCreateChildText(owner, feature, child, selection);
+    if (feature == EcorePackage.Literals.EMODEL_ELEMENT__EANNOTATIONS)
+    {
+      EAnnotation nestedEAnnotation = (EAnnotation)child;
+      String text = getText(nestedEAnnotation);
+      if (text.length() != 0)
+      {
+        result += " - " + text;
+      }
+    }
+    return result;
+  }
+
+  private static final class GroupPropertyDescriptor implements IItemPropertyDescriptor
+  {
+    private String label;
+
+    private String description;
+
+    private Object itemPropertySource;
+
+    public GroupPropertyDescriptor(String label, String description, IItemPropertySource itemPropertySource)
+    {
+      this.label = label;
+      this.description = description;
+      this.itemPropertySource = itemPropertySource;
+    }
+
+    public void setPropertyValue(Object object, Object value)
+    {
+    }
+
+    public void resetPropertyValue(Object object)
+    {
+    }
+
+    public boolean isSortChoices(Object object)
+    {
+      return false;
+    }
+
+    public boolean isPropertySet(Object object)
+    {
+      return false;
+    }
+
+    public boolean isMultiLine(Object object)
+    {
+      return false;
+    }
+
+    public boolean isMany(Object object)
+    {
+      return false;
+    }
+
+    public boolean isCompatibleWith(Object object, Object anotherObject, IItemPropertyDescriptor anotherPropertyDescriptor)
+    {
+      return false;
+    }
+
+    public Object getPropertyValue(Object object)
+    {
+      return itemPropertySource;
+    }
+
+    public IItemLabelProvider getLabelProvider(Object object)
+    {
+      return new IItemLabelProvider()
+        {
+          public String getText(Object object)
+          {
+            return null;
+          }
+
+          public Object getImage(Object object)
+          {
+            return ItemPropertyDescriptor.NO_VALUE_IMAGE;
+          }
+        };
+    }
+
+    public String getId(Object object)
+    {
+      return label;
+    }
+
+    public Object getHelpContextIds(Object object)
+    {
+      return null;
+    }
+
+    public String[] getFilterFlags(Object object)
+    {
+      return null;
+    }
+
+    public Object getFeature(Object object)
+    {
+      return label;
+    }
+
+    public String getDisplayName(Object object)
+    {
+      return label;
+    }
+
+    public String getDescription(Object object)
+    {
+      return description;
+    }
+
+    public Collection<?> getChoiceOfValues(Object object)
+    {
+      return null;
+    }
+
+    public String getCategory(Object object)
+    {
+      return null;
+    }
+
+    public boolean canSetProperty(Object object)
+    {
+      return false;
+    }
+  }
 }
diff --git a/plugins/org.eclipse.emf.ecore.edit/src/org/eclipse/emf/ecore/provider/EClassifierItemProvider.java b/plugins/org.eclipse.emf.ecore.edit/src/org/eclipse/emf/ecore/provider/EClassifierItemProvider.java
index 8ed0da4..36f643e 100644
--- a/plugins/org.eclipse.emf.ecore.edit/src/org/eclipse/emf/ecore/provider/EClassifierItemProvider.java
+++ b/plugins/org.eclipse.emf.ecore.edit/src/org/eclipse/emf/ecore/provider/EClassifierItemProvider.java
@@ -99,6 +99,12 @@
          })
        {
          @Override
+         public boolean isPropertyUnsettable(Object object)
+         {
+           return false;
+         }
+
+         @Override
          public void setPropertyValue(Object object, Object value)
          {
            EObject eObject = (EObject)object;
@@ -179,6 +185,12 @@
          null)
        {
          @Override
+         public boolean isPropertyUnsettable(Object object)
+         {
+           return false;
+         }
+
+         @Override
          public void setPropertyValue(Object object, Object value)
          {
            super.setPropertyValue(object, normalizeInstanceTypeName(stripToNull((String)value)));
diff --git a/plugins/org.eclipse.emf.ecore.edit/src/org/eclipse/emf/ecore/provider/EStringToStringMapEntryItemProvider.java b/plugins/org.eclipse.emf.ecore.edit/src/org/eclipse/emf/ecore/provider/EStringToStringMapEntryItemProvider.java
index 729b354..ae9ddfd 100644
--- a/plugins/org.eclipse.emf.ecore.edit/src/org/eclipse/emf/ecore/provider/EStringToStringMapEntryItemProvider.java
+++ b/plugins/org.eclipse.emf.ecore.edit/src/org/eclipse/emf/ecore/provider/EStringToStringMapEntryItemProvider.java
@@ -18,7 +18,17 @@
 import org.eclipse.emf.common.notify.AdapterFactory;
 import org.eclipse.emf.common.notify.Notification;
 import org.eclipse.emf.common.util.ResourceLocator;
+import org.eclipse.emf.common.util.UniqueEList;
+import org.eclipse.emf.ecore.EAnnotation;
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EModelElement;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EStructuralFeature;
 import org.eclipse.emf.ecore.EcorePackage;
+import org.eclipse.emf.ecore.provider.annotation.EAnnotationItemProviderAdapterFactory;
+import org.eclipse.emf.ecore.util.BasicEAnnotationValidator;
+import org.eclipse.emf.edit.domain.AdapterFactoryEditingDomain;
+import org.eclipse.emf.edit.domain.EditingDomain;
 import org.eclipse.emf.edit.provider.ComposeableAdapterFactory;
 import org.eclipse.emf.edit.provider.IEditingDomainItemProvider;
 import org.eclipse.emf.edit.provider.IItemLabelProvider;
@@ -27,26 +37,31 @@
 import org.eclipse.emf.edit.provider.IStructuredItemContentProvider;
 import org.eclipse.emf.edit.provider.ITreeItemContentProvider;
 import org.eclipse.emf.edit.provider.ItemPropertyDescriptor;
+import org.eclipse.emf.edit.provider.ItemPropertyDescriptorDecorator;
 import org.eclipse.emf.edit.provider.ItemProviderAdapter;
-
 import org.eclipse.emf.edit.provider.ViewerNotification;
 
+
 /**
  * This is the item provider adapter for a {@link java.util.Map.Entry} object.
  * <!-- begin-user-doc -->
+ * This implementation is {@link EAnnotationItemProviderAdapterFactory}-aware using {@link #getEAnnotationItemProviderAdapterFactory()} to drive specialized behavior.
+ * I.e., it behaves differently when created by {@link EcoreItemProviderAdapterFactory} versus when created by {@link EAnnotationItemProviderAdapterFactory}.
  * <!-- end-user-doc -->
  * @generated
  */
-public class EStringToStringMapEntryItemProvider
-  extends ItemProviderAdapter
+public class EStringToStringMapEntryItemProvider extends ItemProviderAdapter
   implements
-    IEditingDomainItemProvider, IStructuredItemContentProvider, ITreeItemContentProvider, IItemLabelProvider, IItemPropertySource
+    IEditingDomainItemProvider,
+    IStructuredItemContentProvider,
+    ITreeItemContentProvider,
+    IItemLabelProvider,
+    IItemPropertySource
 {
   /**
    * This constructs an instance from a factory and a notifier.
    * <!-- begin-user-doc -->
    * <!-- end-user-doc -->
-   * @generated
    */
   public EStringToStringMapEntryItemProvider(AdapterFactory adapterFactory)
   {
@@ -54,13 +69,55 @@
   }
 
   /**
+   * Returns the {@link EAnnotationItemProviderAdapterFactory} if the adapter factory is of that type, <code>null</code> otherwise.
+   * @return the annotation item provider adapter factory or <code>null</code>
+   * @since 2.14
+   */
+  protected EAnnotationItemProviderAdapterFactory getEAnnotationItemProviderAdapterFactory()
+  {
+    return adapterFactory instanceof EAnnotationItemProviderAdapterFactory ? (EAnnotationItemProviderAdapterFactory)adapterFactory : null;
+  }
+
+  /**
+   * Returns the {@link EAnnotationItemProviderAdapterFactory#getAssistant() assistant} of the {@link #getEAnnotationItemProviderAdapterFactory() annotation item provider adapter factory}, if available.
+   * @return the assistant or <code>null</code>.
+   * @since 2.14
+   */
+  protected BasicEAnnotationValidator.Assistant getAssistant()
+  {
+    EAnnotationItemProviderAdapterFactory eAnnotationItemProviderAdapterFactory = getEAnnotationItemProviderAdapterFactory();
+    return eAnnotationItemProviderAdapterFactory == null ? null : eAnnotationItemProviderAdapterFactory.getAssistant();
+  }
+
+  /**
+   * Returns the containing annotation of the given annotation detail.
+   *
+   * @since 2.14
+   */
+  protected EAnnotation getEAnnotation(Object object)
+  {
+    EObject eContainer = ((EObject)object).eContainer();
+    return eContainer instanceof EAnnotation ? (EAnnotation)eContainer : null;
+  }
+
+  /**
+   * Returns the containing model element of the {@link #getEAnnotation(Object) containing annotation}.
+   *
+   * @since 2.14
+   */
+  protected EModelElement getEModelElement(Object object)
+  {
+    EAnnotation eAnnotation = getEAnnotation(object);
+    return eAnnotation != null ? eAnnotation.getEModelElement() : null;
+  }
+
+  /**
    * This returns the property descriptors for the adapted class.
    * <!-- begin-user-doc -->
    * <!-- end-user-doc -->
    * @generated
    */
-  @Override
-  public List<IItemPropertyDescriptor> getPropertyDescriptors(Object object)
+  protected List<IItemPropertyDescriptor> getPropertyDescriptorsGen(Object object)
   {
     if (itemPropertyDescriptors == null)
     {
@@ -73,49 +130,337 @@
   }
 
   /**
+   * {@inheritDoc}
+   * <p>
+   * This implementation is specialized to clear the cached {@link #itemPropertyDescriptors descriptors} if this adapter was created by an {@link EAnnotationItemProviderAdapterFactory}.
+   * <p>
+   */
+  @Override
+  public List<IItemPropertyDescriptor> getPropertyDescriptors(Object object)
+  {
+    if (getEAnnotationItemProviderAdapterFactory() != null)
+    {
+      itemPropertyDescriptors = null;
+    }
+
+    List<IItemPropertyDescriptor> propertyDescriptors = getPropertyDescriptorsGen(object);
+    return propertyDescriptors;
+  }
+
+  /**
    * This adds a property descriptor for the Key feature.
    * <!-- begin-user-doc -->
+   * This implementation is specialized to call {@link #createKeyPropertyDescriptor(Map.Entry)}.
    * <!-- end-user-doc -->
-   * @generated
+   * @generated NOT
    */
   protected void addKeyPropertyDescriptor(Object object)
   {
-    itemPropertyDescriptors.add
-      (createItemPropertyDescriptor
-        (((ComposeableAdapterFactory)adapterFactory).getRootAdapterFactory(),
-         getResourceLocator(),
-         getString("_UI_EStringToStringMapEntry_key_feature"),
-         getString("_UI_EStringToStringMapEntry_key_description"),
-         EcorePackage.Literals.ESTRING_TO_STRING_MAP_ENTRY__KEY,
-         true,
-         false,
-         false,
-         ItemPropertyDescriptor.GENERIC_VALUE_IMAGE,
-         null,
-         null));
+    @SuppressWarnings("unchecked")
+    Map.Entry<String, String> entry = (Map.Entry<String, String>)object;
+    itemPropertyDescriptors.add(createKeyPropertyDescriptor(entry));
+  }
+
+  /**
+   * Creates the property descriptor for the entry's key.
+   * <p>
+   * This implementation creates specialized instance of property descriptor
+   * that delegates {@link ItemPropertyDescriptor#getChoiceOfValues(Object)} to {@link #getKeyChoiceOfValues(Map.Entry)},
+   * that delegates {@link ItemPropertyDescriptor#isSortChoices(Object)} to {@link #isKeySortChoices(Map.Entry)},
+   * and returns <code>true</code> for {@link ItemPropertyDescriptor#isChoiceArbitrary(Object)}.
+   * </p>
+   * @param entry the detail entry.
+   * @return the property descriptor for the entry's key.
+   *
+   * @since 2.14
+   */
+  protected IItemPropertyDescriptor createKeyPropertyDescriptor(Map.Entry<String, String> entry)
+  {
+    return new ValueHandlingPropertyDescriptor(
+      ((ComposeableAdapterFactory)adapterFactory).getRootAdapterFactory(),
+      getResourceLocator(),
+      getString("_UI_EStringToStringMapEntry_key_feature"),
+      getString("_UI_EStringToStringMapEntry_key_description"),
+      EcorePackage.Literals.ESTRING_TO_STRING_MAP_ENTRY__KEY,
+      true,
+      false,
+      isKeySortChoices(entry),
+      ItemPropertyDescriptor.GENERIC_VALUE_IMAGE,
+      null,
+      null)
+      {
+        @Override
+        public Collection<?> getChoiceOfValues(Object object)
+        {
+          @SuppressWarnings("unchecked")
+          Map.Entry<String, String> entry = (Map.Entry<String, String>)object;
+          return getKeyChoiceOfValues(entry);
+        }
+      };
+  }
+
+  /**
+   * Returns whether this entry supports {@link IItemPropertyDescriptor#isSortChoices(Object) sorting} choices for the property descriptor for the value.
+   * <p>
+   * This implementation always returns <code>true</code>
+   * </p>
+   * @param entry the entry to test.
+   * @return whether this entry supports sorting choices for the property descriptor for the value.
+   * @since 2.14
+   */
+  protected boolean isKeySortChoices(Map.Entry<String, String> entry)
+  {
+    return true;
+  }
+
+  /**
+   * Returns the choices for the value feature.
+   * <p>
+   * This implementation uses the {@link #getEAnnotationItemProviderAdapterFactory()} {@link EAnnotationItemProviderAdapterFactory#getAssistant() assistant}
+   * to {@link org.eclipse.emf.ecore.util.BasicEAnnotationValidator.Assistant#createInstance(EClass, EAnnotation) create} modeled objects and uses
+   * the keys of their {@link org.eclipse.emf.ecore.util.BasicEAnnotationValidator.Assistant#getApplicableProperties(EObject, EAnnotation) applicable properties}
+   * to build a set of valid keys, removing any keys already in the {@link EAnnotation#getDetails() details},
+   * and then including the current value of the entry's key.
+   * Otherwise it returns <code>null</code>
+   * </p>
+   * @param entry the entry.
+   * @return the choices for the value feature.
+   * @since 2.14
+   */
+  protected Collection<?> getKeyChoiceOfValues(Map.Entry<String, String> entry)
+  {
+    BasicEAnnotationValidator.Assistant assistant = getAssistant();
+    if (assistant != null)
+    {
+      EModelElement eModelElement = getEModelElement(entry);
+      if (eModelElement != null)
+      {
+        EAnnotation eAnnotation = getEAnnotation(entry);
+        List<String> result = new UniqueEList<String>();
+        for (EClass eClass : assistant.getPropertyClasses(eModelElement))
+        {
+          EObject instance = assistant.createInstance(eClass, eAnnotation);
+          result.addAll(assistant.getApplicableProperties(instance, eAnnotation).keySet());
+        }
+
+        // Remove any property names already used within the annotation.
+        result.removeAll(eAnnotation.getDetails().keySet());
+
+        // Add the entry's key, if it's not null.
+        String key = entry.getKey();
+        result.add(key);
+
+        return result;
+      }
+    }
+    return null;
   }
 
   /**
    * This adds a property descriptor for the Value feature.
    * <!-- begin-user-doc -->
+   * This implementation is specialized to delegate to {@link #createValuePropertyDescriptor(Map.Entry)}.
    * <!-- end-user-doc -->
-   * @generated
+   * @generated NOT
    */
   protected void addValuePropertyDescriptor(Object object)
   {
-    itemPropertyDescriptors.add
-      (createItemPropertyDescriptor
-        (((ComposeableAdapterFactory)adapterFactory).getRootAdapterFactory(),
-         getResourceLocator(),
-         getString("_UI_EStringToStringMapEntry_value_feature"),
-         getString("_UI_EStringToStringMapEntry_value_description"),
-         EcorePackage.Literals.ESTRING_TO_STRING_MAP_ENTRY__VALUE,
-         true,
-         true,
-         false,
-         ItemPropertyDescriptor.GENERIC_VALUE_IMAGE,
-         null,
-         null));
+    @SuppressWarnings("unchecked")
+    Map.Entry<String, String> entry = (Map.Entry<String, String>)object;
+    itemPropertyDescriptors.add(createValuePropertyDescriptor(entry));
+  }
+
+  /**
+   * Creates the property descriptor the entry's value.
+   * <p>
+   * This implementation creates specialized instance of property descriptor
+   * that delegates {@link ItemPropertyDescriptor#getChoiceOfValues(Object)} to {@link #getValueChoiceOfValues(Map.Entry)},
+   * that delegates {@link ItemPropertyDescriptor#isMultiLine(Object)} to {@link #isValueMultiLine(Map.Entry)},
+   * that delegates {@link ItemPropertyDescriptor#isSortChoices(Object)} to {@link #isValueSortChoices(Map.Entry)},
+   * and returns <code>true</code> for {@link ItemPropertyDescriptor#isChoiceArbitrary(Object)}.
+   * </p>
+   * <p>
+   * <p>
+   * This implementation uses the {@link #getEAnnotationItemProviderAdapterFactory()} {@link EAnnotationItemProviderAdapterFactory#getAssistant() assistant}
+   * to {@link org.eclipse.emf.ecore.util.BasicEAnnotationValidator.Assistant#createInstance(EClass, EAnnotation) create} modeled objects, when available.
+   * If the entry corresponds one of the modeled object's {@link org.eclipse.emf.ecore.util.BasicEAnnotationValidator.Assistant#getApplicableProperties(EObject, EAnnotation) applicable properties},
+   * it {@link EAnnotationItemProviderAdapterFactory#getPropertyDescriptor(EObject, String, EStructuralFeature, EAnnotation, ResourceLocator) gets the property descriptor} for that object,
+   * {@link EAnnotationItemProviderAdapterFactory#createPropertyDescriptorDecorator(IItemPropertyDescriptor, EObject, String, EStructuralFeature, EAnnotation, ResourceLocator, EditingDomain) creates a decorate} for descriptor,
+   * and finally creates yet another decorator that that decorator
+   * that makes the property look and behave like a regular value property descriptor, except that the description, value handling, and cell editor is that of the modeled object.
+   * </p>
+   * </p>
+   * @param entry the detail entry.
+   * @return the property descriptor for the entry's value.
+   * @since 2.14
+   */
+  protected IItemPropertyDescriptor createValuePropertyDescriptor(final Map.Entry<String, String> entry)
+  {
+    final IItemPropertyDescriptor valuePropertyDescriptor = new ValueHandlingPropertyDescriptor(
+      ((ComposeableAdapterFactory)adapterFactory).getRootAdapterFactory(),
+      getResourceLocator(),
+      getString("_UI_EStringToStringMapEntry_value_feature"),
+      getString("_UI_EStringToStringMapEntry_value_description"),
+      EcorePackage.Literals.ESTRING_TO_STRING_MAP_ENTRY__VALUE,
+      true,
+      isValueMultiLine(entry),
+      isValueSortChoices(entry),
+      ItemPropertyDescriptor.GENERIC_VALUE_IMAGE,
+      null,
+      null)
+      {
+        @Override
+        public Collection<?> getChoiceOfValues(Object object)
+        {
+          @SuppressWarnings("unchecked")
+          Map.Entry<String, String> entry = (Map.Entry<String, String>)object;
+          return getValueChoiceOfValues(entry);
+        }
+      };
+    EAnnotationItemProviderAdapterFactory eAnnotationItemProviderAdapterFactory = getEAnnotationItemProviderAdapterFactory();
+    BasicEAnnotationValidator.Assistant assistant = getAssistant();
+    if (eAnnotationItemProviderAdapterFactory != null && assistant != null)
+    {
+      EModelElement eModelElement = getEModelElement(entry);
+      if (eModelElement != null)
+      {
+        EAnnotation eAnnotation = getEAnnotation(entry);
+        List<EClass> propertyClasses = assistant.getPropertyClasses(eModelElement);
+        String key = entry.getKey();
+        for (EClass eClass : propertyClasses)
+        {
+          EObject instance = assistant.createInstance(eClass, eAnnotation);
+          Map<String, EStructuralFeature> applicableProperties = assistant.getApplicableProperties(instance, eAnnotation);
+          EStructuralFeature eStructuralFeature = applicableProperties.get(key);
+          if (eClass.getEAllStructuralFeatures().contains(eStructuralFeature))
+          {
+            IItemPropertyDescriptor itemPropertyDescriptor = eAnnotationItemProviderAdapterFactory.getPropertyDescriptor(
+              instance,
+              key,
+              eStructuralFeature,
+              eAnnotation,
+              getResourceLocator());
+
+            EditingDomain domain = AdapterFactoryEditingDomain.getEditingDomainFor(eAnnotation);
+            IItemPropertyDescriptor decoratedItemPropertyDescriptor = eAnnotationItemProviderAdapterFactory.createPropertyDescriptorDecorator(
+              itemPropertyDescriptor,
+              instance,
+              key,
+              eStructuralFeature,
+              eAnnotation,
+              getResourceLocator(),
+              domain);
+
+            return new ItemPropertyDescriptorDecorator(entry, decoratedItemPropertyDescriptor)
+              {
+                @Override
+                public String getDisplayName(Object thisObject)
+                {
+                  return valuePropertyDescriptor.getDisplayName(entry);
+                }
+
+                @Override
+                public String getCategory(Object thisObject)
+                {
+                  return null;
+                }
+
+                @Override
+                public String[] getFilterFlags(Object thisObject)
+                {
+                  return null;
+                }
+
+                @Override
+                public boolean isPropertySet(Object thisObject)
+                {
+                  return valuePropertyDescriptor.isPropertySet(entry);
+                }
+
+                @Override
+                public void resetPropertyValue(Object thisObject)
+                {
+                  valuePropertyDescriptor.resetPropertyValue(entry);
+                }
+
+                @Override
+                public boolean isPropertyUnsettable(Object object)
+                {
+                  Object propertyValue = getPropertyValue(object);
+                  return propertyValue != null;
+                }
+              };
+          }
+        }
+      }
+    }
+
+    return valuePropertyDescriptor;
+  }
+
+  private static class ValueHandlingPropertyDescriptor extends ItemPropertyDescriptor
+  {
+    public ValueHandlingPropertyDescriptor(
+      AdapterFactory adapterFactory,
+      ResourceLocator resourceLocator,
+      String displayName,
+      String description,
+      EStructuralFeature feature,
+      boolean isSettable,
+      boolean multiLine,
+      boolean sortChoices,
+      Object staticImage,
+      String category,
+      String[] filterFlags)
+    {
+      super(adapterFactory, resourceLocator, displayName, description, feature, isSettable, multiLine, sortChoices, staticImage, category, filterFlags);
+    }
+
+    @Override
+    public boolean isChoiceArbitrary(Object object)
+    {
+      return true;
+    }
+  }
+
+  /**
+   * Returns whether this entry supports a {@link IItemPropertyDescriptor#isMultiLine(Object) multi-line} property descriptor for the value feature.
+   * <p>
+   * This implementation always returns <code>true</code>.
+   * </p>
+   * @param entry the entry in question.
+   * @return whether this entry supported a multi-line property descriptor for the value.
+   * @since 2.14
+   */
+  protected boolean isValueMultiLine(Map.Entry<String, String> entry)
+  {
+    return true;
+  }
+
+  /**
+   * Returns whether this entry supports {@link IItemPropertyDescriptor#isSortChoices(Object) sorting} choices for the property descriptor for the value feature.
+   * <p>
+   * This implementation always returns <code>true</code>.
+   * </p>
+   * @param entry the entry to test.
+   * @return whether this entry supports a sorting choices for the property descriptor for the value.
+   * @since 2.14
+   */
+  protected boolean isValueSortChoices(Map.Entry<String, String> entry)
+  {
+    return true;
+  }
+
+  /**
+   * Returns the choices for the value feature.
+   * This implementation always returns <code>null</code>.
+   * @param entry the entry.
+   * @return the choices for the value feature.
+   * @since 2.14
+   */
+  protected Collection<?> getValueChoiceOfValues(Map.Entry<String, String> entry)
+  {
+    return null;
   }
 
   /**
@@ -191,5 +536,4 @@
   {
     return EcoreEditPlugin.INSTANCE;
   }
-
 }
diff --git a/plugins/org.eclipse.emf.ecore.edit/src/org/eclipse/emf/ecore/provider/EcoreEditPlugin.java b/plugins/org.eclipse.emf.ecore.edit/src/org/eclipse/emf/ecore/provider/EcoreEditPlugin.java
index 0aa6bf7..cbfde38 100644
--- a/plugins/org.eclipse.emf.ecore.edit/src/org/eclipse/emf/ecore/provider/EcoreEditPlugin.java
+++ b/plugins/org.eclipse.emf.ecore.edit/src/org/eclipse/emf/ecore/provider/EcoreEditPlugin.java
@@ -11,9 +11,15 @@
 package org.eclipse.emf.ecore.provider;
 
 
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.RegistryFactory;
 import org.eclipse.emf.common.EMFPlugin;
 import org.eclipse.emf.common.util.ResourceLocator;
+import org.eclipse.emf.ecore.plugin.EcorePlugin;
+import org.eclipse.emf.ecore.plugin.RegistryReader;
+import org.eclipse.emf.ecore.provider.annotation.EAnnotationItemProviderAdapterFactory;
 import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
 
 
 /**
@@ -102,6 +108,13 @@
       plugin = this;
     }
 
+    @Override
+    public void start(BundleContext context) throws Exception
+    {
+      super.start(context);
+      new AnnotationItemProviderAdapterFactoryRegistryReader().readRegistry();
+    }
+
     /**
      * The actual implementation of the purely OSGi-compatible <b>Bundle Activator</b>.
      * <!-- begin-user-doc -->
@@ -118,3 +131,67 @@
     }
   }
 }
+
+class AnnotationItemProviderAdapterFactoryRegistryReader extends RegistryReader
+{
+  static class AnnotationItemProviderAdapterFactoryDescriptor extends PluginClassDescriptor implements EAnnotationItemProviderAdapterFactory.Factory
+  {
+    public AnnotationItemProviderAdapterFactoryDescriptor(IConfigurationElement e, String attrName)
+    {
+      super(e, attrName);
+    }
+
+    public EAnnotationItemProviderAdapterFactory createEAnnotationItemProviderAdapterFactory()
+    {
+      return (EAnnotationItemProviderAdapterFactory)createInstance();
+    }
+ 
+    public IConfigurationElement getElement()
+    {
+      return element;
+    }
+  }
+
+  static final String TAG_FACTORY = "factory";
+  static final String ATT_URI = "uri";
+  static final String ATT_CLASS = "class";
+
+  public AnnotationItemProviderAdapterFactoryRegistryReader()
+  {
+    super(RegistryFactory.getRegistry(), EcoreEditPlugin.INSTANCE.getSymbolicName(), "annotation_item_provider_adapter_factory");
+  }
+
+  @Override
+  protected boolean readElement(IConfigurationElement element, boolean add)
+  {
+    if (element.getName().equals(TAG_FACTORY))
+    {
+      String uri = element.getAttribute(ATT_URI);
+      if (uri == null)
+      {
+        logMissingAttribute(element, ATT_URI);
+      }
+      else if (element.getAttribute(ATT_CLASS) == null)
+      {
+        logMissingAttribute(element, ATT_CLASS);
+      }
+      else if (add)
+      {
+        Object previous = EAnnotationItemProviderAdapterFactory.Registry.INSTANCE.put(uri, new AnnotationItemProviderAdapterFactoryDescriptor(element, ATT_CLASS));
+        if (previous instanceof AnnotationItemProviderAdapterFactoryDescriptor)
+        {
+          AnnotationItemProviderAdapterFactoryDescriptor descriptor = (AnnotationItemProviderAdapterFactoryDescriptor)previous;
+          EcorePlugin.INSTANCE.log("Both '" + descriptor.getElement().getContributor().getName() + "' and '" + element.getContributor().getName() + "' register an annotation item provider adapter factory for '" + uri + "'");
+        }
+        return true;
+      }
+      else
+      {
+        EAnnotationItemProviderAdapterFactory.Registry.INSTANCE.remove(uri);
+        return true;
+      }
+    }
+
+    return false;
+  }
+}
diff --git a/plugins/org.eclipse.emf.ecore.edit/src/org/eclipse/emf/ecore/provider/EcoreItemProviderAdapterFactory.java b/plugins/org.eclipse.emf.ecore.edit/src/org/eclipse/emf/ecore/provider/EcoreItemProviderAdapterFactory.java
index 45a1030..0b572a8 100644
--- a/plugins/org.eclipse.emf.ecore.edit/src/org/eclipse/emf/ecore/provider/EcoreItemProviderAdapterFactory.java
+++ b/plugins/org.eclipse.emf.ecore.edit/src/org/eclipse/emf/ecore/provider/EcoreItemProviderAdapterFactory.java
@@ -13,11 +13,17 @@
 
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
 
 import org.eclipse.emf.common.notify.Adapter;
 import org.eclipse.emf.common.notify.Notification;
 import org.eclipse.emf.common.notify.Notifier;
+import org.eclipse.emf.ecore.EAnnotation;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.provider.annotation.EAnnotationItemProviderAdapterFactory;
 import org.eclipse.emf.ecore.util.EcoreAdapterFactory;
+import org.eclipse.emf.ecore.util.EcoreSwitch;
 import org.eclipse.emf.edit.provider.ChangeNotifier;
 import org.eclipse.emf.edit.provider.ComposeableAdapterFactory;
 import org.eclipse.emf.edit.provider.ComposedAdapterFactory;
@@ -38,6 +44,11 @@
  * The adapters also support Eclipse property sheets.
  * Note that most of the adapters are shared among multiple instances.
  * <!-- begin-user-doc -->
+ * <p>
+ * This implementation is specialized {@link #adapt(Notifier, Object)} to use the {@link EAnnotationItemProviderAdapterFactory}.
+ * It maintains a {@link #eAnnotationItemProviderAdapterFactories map} from {@link EAnnotation#getSource() annotation source} to EAnnotationItemProviderAdapterFactory,
+ * which it uses to create specialized instances of {@link EAnnotationItemProvider} and {@link EStringToStringMapEntryItemProvider}.
+ * </p>
  * <!-- end-user-doc -->
  * @generated
  */
@@ -68,6 +79,11 @@
   protected Collection<Object> supportedTypes = new ArrayList<Object>();
 
   /**
+   * @since 2.14
+   */
+  protected Map<String, EAnnotationItemProviderAdapterFactory> eAnnotationItemProviderAdapterFactories = new HashMap<String, EAnnotationItemProviderAdapterFactory>();
+
+  /**
    * This constructs an instance.
    * <!-- begin-user-doc -->
    * <!-- end-user-doc -->
@@ -493,13 +509,60 @@
   /**
    * This implementation substitutes the factory itself as the key for the adapter.
    * <!-- begin-user-doc -->
+   * <p>
+   * This method is specialized to use {@link EAnnotationItemProviderAdapterFactory}.
+   * </p>
    * <!-- end-user-doc -->
-   * @generated
+   * @generated NOT
    */
   @Override
-  public Adapter adapt(Notifier notifier, Object type)
+  public Adapter adapt(Notifier notifier, final Object type)
   {
-    return super.adapt(notifier, this);
+    EcoreSwitch<Adapter> annotationSwitch =
+      new EcoreSwitch<Adapter>()
+      {
+        protected EAnnotationItemProviderAdapterFactory getEAnnotationItemProviderAdapterFactory(EAnnotation eAnnotation)
+        {
+          String annotationSource = eAnnotation.getSource();
+          EAnnotationItemProviderAdapterFactory eAnnotationItemProviderAdapterFactory = eAnnotationItemProviderAdapterFactories.get(annotationSource);
+          if (eAnnotationItemProviderAdapterFactory == null)
+          {
+            eAnnotationItemProviderAdapterFactory = EAnnotationItemProviderAdapterFactory.Registry.INSTANCE.createEAnnotationItemProviderAdapterFactory(annotationSource);
+            if (eAnnotationItemProviderAdapterFactory != null)
+            {
+              eAnnotationItemProviderAdapterFactory.setParentAdapterFactory(EcoreItemProviderAdapterFactory.this);
+              eAnnotationItemProviderAdapterFactories.put(annotationSource, eAnnotationItemProviderAdapterFactory);
+            }
+          }
+          return eAnnotationItemProviderAdapterFactory;
+        }
+
+        @Override
+        public Adapter caseEAnnotation(EAnnotation eAnnotation)
+        {
+          EAnnotationItemProviderAdapterFactory eAnnotationItemProviderAdapterFactory = getEAnnotationItemProviderAdapterFactory(eAnnotation);
+          return eAnnotationItemProviderAdapterFactory == null ? null : eAnnotationItemProviderAdapterFactory.adapt(eAnnotation, type);
+        }
+
+        @Override
+        public Adapter caseEStringToStringMapEntry(Map.Entry<String, String> object)
+        {
+          EObject eObject = (EObject)object;
+          EObject eContainer = eObject.eContainer();
+          if (eContainer instanceof EAnnotation)
+          {
+            EAnnotationItemProviderAdapterFactory eAnnotationItemProviderAdapterFactory = getEAnnotationItemProviderAdapterFactory((EAnnotation)eContainer);
+            return eAnnotationItemProviderAdapterFactory == null ? null : eAnnotationItemProviderAdapterFactory.adapt(eObject, type);
+          }
+          else
+          {
+            return null;
+          }
+        }
+      };
+
+    Adapter result = annotationSwitch.doSwitch((EObject)notifier);
+    return result != null ? result : super.adapt(notifier, this);
   }
 
   /**
@@ -566,7 +629,7 @@
    * <!-- end-user-doc -->
    * @generated
    */
-  public void dispose()
+  private void disposeGen()
   {
     if (eAttributeItemProvider != null) eAttributeItemProvider.dispose();
     if (eAnnotationItemProvider != null) eAnnotationItemProvider.dispose();
@@ -585,4 +648,13 @@
     if (eTypeParameterItemProvider != null) eTypeParameterItemProvider.dispose();
   }
 
+  public void dispose()
+  {
+    disposeGen();
+    for (EAnnotationItemProviderAdapterFactory eAnnotationItemProviderAdapterFactory : eAnnotationItemProviderAdapterFactories.values())
+    {
+      eAnnotationItemProviderAdapterFactory.dispose();
+    }
+    eAnnotationItemProviderAdapterFactories.clear();
+  }
 }
diff --git a/plugins/org.eclipse.emf.ecore.edit/src/org/eclipse/emf/ecore/provider/annotation/EAnnotationItemProviderAdapterFactory.java b/plugins/org.eclipse.emf.ecore.edit/src/org/eclipse/emf/ecore/provider/annotation/EAnnotationItemProviderAdapterFactory.java
new file mode 100644
index 0000000..858380a
--- /dev/null
+++ b/plugins/org.eclipse.emf.ecore.edit/src/org/eclipse/emf/ecore/provider/annotation/EAnnotationItemProviderAdapterFactory.java
@@ -0,0 +1,788 @@
+/**
+ * Copyright (c) 2017 Eclipse contributes and others.
+ * All rights reserved.   This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.eclipse.emf.ecore.provider.annotation;
+
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.emf.common.notify.Adapter;
+import org.eclipse.emf.common.notify.Notification;
+import org.eclipse.emf.common.notify.Notifier;
+import org.eclipse.emf.common.notify.impl.AdapterFactoryImpl;
+import org.eclipse.emf.common.util.EList;
+import org.eclipse.emf.common.util.EMap;
+import org.eclipse.emf.common.util.ResourceLocator;
+import org.eclipse.emf.ecore.EAnnotation;
+import org.eclipse.emf.ecore.EAnnotationValidator;
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EModelElement;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EStructuralFeature;
+import org.eclipse.emf.ecore.EcorePackage;
+import org.eclipse.emf.ecore.provider.EAnnotationItemProvider;
+import org.eclipse.emf.ecore.provider.EStringToStringMapEntryItemProvider;
+import org.eclipse.emf.ecore.provider.EcoreItemProviderAdapterFactory;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.emf.ecore.util.BasicEAnnotationValidator;
+import org.eclipse.emf.ecore.util.EcoreSwitch;
+import org.eclipse.emf.ecore.util.EcoreUtil;
+import org.eclipse.emf.edit.command.AddCommand;
+import org.eclipse.emf.edit.command.RemoveCommand;
+import org.eclipse.emf.edit.command.SetCommand;
+import org.eclipse.emf.edit.domain.AdapterFactoryEditingDomain;
+import org.eclipse.emf.edit.domain.EditingDomain;
+import org.eclipse.emf.edit.provider.ChangeNotifier;
+import org.eclipse.emf.edit.provider.ComposeableAdapterFactory;
+import org.eclipse.emf.edit.provider.ComposedAdapterFactory;
+import org.eclipse.emf.edit.provider.Disposable;
+import org.eclipse.emf.edit.provider.IChangeNotifier;
+import org.eclipse.emf.edit.provider.IDisposable;
+import org.eclipse.emf.edit.provider.IEditingDomainItemProvider;
+import org.eclipse.emf.edit.provider.IItemLabelProvider;
+import org.eclipse.emf.edit.provider.IItemPropertyDescriptor;
+import org.eclipse.emf.edit.provider.IItemPropertySource;
+import org.eclipse.emf.edit.provider.INotifyChangedListener;
+import org.eclipse.emf.edit.provider.IStructuredItemContentProvider;
+import org.eclipse.emf.edit.provider.ITreeItemContentProvider;
+import org.eclipse.emf.edit.provider.ItemPropertyDescriptorDecorator;
+import org.eclipse.emf.edit.provider.ReflectiveItemProviderAdapterFactory;
+
+
+/**
+ * A base class for supporting the specialization of {@link EAnnotationItemProvider} and {@link EStringToStringMapEntryItemProvider}.
+ * <p>
+ * The {@link EcoreItemProviderAdapterFactory} has a specialized {@link EcoreItemProviderAdapterFactory#adapt(Notifier, Object) adapt} method
+ * that uses this class' {@link Registry} to {@link Registry#createEAnnotationItemProviderAdapterFactory(String) create} specialized implementations of this factory
+ * depending on the {@link EAnnotation#getSource() annotation's source}.
+ * Before {@link EcoreItemProviderAdapterFactory#createEAnnotationAdapter() creating} an EAnnotationItemProvider 
+ * or {@link EcoreItemProviderAdapterFactory#createEStringToStringMapEntryAdapter() creating} an EStringToStringMapEntryItemProvider,
+ * EcoreItemProviderAdapterFactory will call {@link #createEAnnotationAdapter()} or {@link #createEStringToStringMapEntryAdapter()} on this factory.
+ * If this factory returns one, that one will be used.
+ * When EcoreItemProviderAdapterFactory creates an instance of this class,
+ * it calls {@link #setParentAdapterFactory(EcoreItemProviderAdapterFactory)} so that this factory has a path back to the {@link #getRootAdapterFactory()}.
+ * When EcoreItemProviderAdapterFactory is {@link EcoreItemProviderAdapterFactory#dispose() disposed} it will {@link #dispose() dispose} this factory.
+ * </p>
+ * By default,
+ * the {@link #createEAnnotationAdapter()} and the {@link #createEStringToStringMapEntryAdapter()} simply create an EAnnotationItemProvider or an EStringToStringMapEntryItemProvider,
+ * passing in this factory to the constructors.
+ * <p>
+ * All methods are implemented by this class, 
+ * but the factory is abstract because it's expected that a derived class will specialize some of the methods.
+ * A derived class could override {@link #doCreateEAnnotationAdapter()}, {@link #doCreateEStringToStringMapEntryAdapter()}, or both in order to support specialized stateless adapters.
+ * A derived class could instead override {@link #createEAnnotationAdapter()}, {@link #createEStringToStringMapEntryAdapter()}, or both in order to support specialized stateful adapters.
+ * However, based on {@link EAnnotationItemProvider#getEAnnotationItemProviderAdapterFactory()} and {@link EStringToStringMapEntryItemProvider#getEAnnotationItemProviderAdapterFactory()},
+ * both existing implementations are specialized to delegate back to this factory's 
+ * {@link #getPropertyDescriptor(EObject, String, EStructuralFeature, EAnnotation, ResourceLocator) getPropertyDescriptor}, 
+ * {@link #getPropertyDescriptors(EObject, EAnnotation, ResourceLocator) getPropertyDescriptors},
+ * and {@link #createPropertyDescriptorDecorator(IItemPropertyDescriptor, EObject, String, EStructuralFeature, EAnnotation, ResourceLocator, EditingDomain) createPropertyDescriptorDecorator} methods,
+ * so those are the methods most likely to be specialized.
+ * </p>
+ * <p>
+ * It's generally expected that there will be a corresponding {@link EAnnotationValidator} also associated with the annotation source  which which this factory provides specialized adapters.
+ * That annotation validator's {@link org.eclipse.emf.ecore.util.BasicEAnnotationValidator.Assistant assistant} is used to drive much of the specialized behavior.
+ * </p>
+ *
+ * @since 2.14
+ */
+public abstract class EAnnotationItemProviderAdapterFactory extends AdapterFactoryImpl implements ComposeableAdapterFactory, IChangeNotifier, IDisposable
+{
+  /**
+   * An <code>EAnnotationItemProviderAdapterFactory</code> factory that is used by the {@link EAnnotationItemProviderAdapterFactory.Registry}.
+   */
+  public interface Factory
+  {
+    /**
+     * Creates an annotation item provider adapter factory.
+     * @return an annotation item provider adapter factory.
+     */
+    EAnnotationItemProviderAdapterFactory createEAnnotationItemProviderAdapterFactory();
+  }
+
+  /**
+   * A map from {@link EAnnotation#getSource() annotation source} to {@link EAnnotationItemProviderAdapterFactory.Factory}.
+   */
+  public interface Registry extends Map<String, Factory>
+  {
+    /**
+     * Creates an annotation item provider adapter factory for the given {@link EAnnotation#getSource() annotation source}.
+     * @param annotationSoure the annotation source.
+     * @return an annotation item provider adapter factory or <code>null</code> if there is no registered factory.
+     */
+    EAnnotationItemProviderAdapterFactory createEAnnotationItemProviderAdapterFactory(String annotationSoure);
+
+    /**
+     * The global instance of an annotation item provider adapter factory registry.
+     */
+    Registry INSTANCE = new Impl();
+
+    /**
+     * A trivial registry implementation.
+     *
+     */
+    class Impl extends HashMap<String, EAnnotationItemProviderAdapterFactory.Factory> implements Registry
+    {
+      private static final long serialVersionUID = 1L;
+
+      public EAnnotationItemProviderAdapterFactory createEAnnotationItemProviderAdapterFactory(String annotationSource)
+      {
+        EAnnotationItemProviderAdapterFactory.Factory factory = get(annotationSource);
+        return factory == null ? null : factory.createEAnnotationItemProviderAdapterFactory();
+      }
+    }
+  }
+
+  /**
+   * This is used to implement {@link org.eclipse.emf.edit.provider.IChangeNotifier}.
+   */
+  protected final IChangeNotifier changeNotifier = new ChangeNotifier();
+
+  /**
+   * This keeps track of all the supported types checked by {@link #isFactoryForType isFactoryForType}.
+   */
+  protected final Collection<Object> supportedTypes = new ArrayList<Object>();
+
+  /**
+   * This is used to implement {@link org.eclipse.emf.edit.provider.IDisposable}.
+   */
+  protected final Disposable disposable = new Disposable();
+
+  /**
+   * The switch that delegates to {@link #createEAnnotationAdapter()} or {@link #createEStringToStringMapEntryAdapter()} as appropriate.
+   */
+  protected final EcoreSwitch<Adapter> modelSwitch = new EcoreSwitch<Adapter>()
+    {
+      @Override
+      public Adapter caseEAnnotation(EAnnotation object)
+      {
+        return createEAnnotationAdapter();
+      }
+
+      @Override
+      public Adapter caseEStringToStringMapEntry(Map.Entry<String, String> object)
+      {
+        return createEStringToStringMapEntryAdapter();
+      }
+    };
+
+  /**
+   * The assistant provided in the constructor and returned by {@link #getAssistant()}.
+   */
+  protected final BasicEAnnotationValidator.Assistant assistant;
+
+  /**
+   * The resource locator provided in the constructor and returned by {@link #getResourceLocator()}.
+   */
+  protected final ResourceLocator resourceLocator;
+
+  /**
+   * This keeps track of the Ecore item provider adapter factory that delegates to this adapter factory.
+   */
+  protected EcoreItemProviderAdapterFactory ecoreItemProviderAdapterFactory;
+
+  /**
+   * This keeps track of the one adapter used for all {@link org.eclipse.emf.ecore.EAnnotation} instances.
+   */
+  protected Adapter eAnnotationItemProvider;
+
+  /**
+   * This keeps track of the one adapter used for all {@link java.util.Map.Entry} instances.
+   */
+  protected Adapter eStringToStringMapEntryItemProvider;
+
+  /**
+   * This constructs an instance given a resource locator and an annotation assistant.
+   */
+  public EAnnotationItemProviderAdapterFactory(ResourceLocator resourceLocator, BasicEAnnotationValidator.Assistant assistant)
+  {
+    this.resourceLocator = resourceLocator;
+    this.assistant = assistant;
+
+    supportedTypes.add(IEditingDomainItemProvider.class);
+    supportedTypes.add(IStructuredItemContentProvider.class);
+    supportedTypes.add(ITreeItemContentProvider.class);
+    supportedTypes.add(IItemLabelProvider.class);
+    supportedTypes.add(IItemPropertySource.class);
+  }
+
+  /**
+   * Returns the assistant.
+   * <p>
+   * The assistant is used by the implementations of {@link EAnnotationItemProvider} and {@link EStringToStringMapEntryItemProvider}.
+   * </p>
+   * @return the assistant.
+   * @see EAnnotationItemProvider.SourcePropertyDescriptor#getAssistant()
+   * @see EAnnotationItemProvider#addReferencesPropertyDescriptor(Object)
+   * @see EStringToStringMapEntryItemProvider#createValuePropertyDescriptor(Map.Entry)
+   * @see EStringToStringMapEntryItemProvider#getKeyChoiceOfValues(Map.Entry)
+   */
+  public BasicEAnnotationValidator.Assistant getAssistant()
+  {
+    return assistant;
+  }
+
+  /**
+   * Returns whether {@link EAnnotationItemProvider.SourcePropertyDescriptor#createPropertyValueWrapper(Object, Object)} 
+   * should show the {@link org.eclipse.emf.ecore.util.BasicEAnnotationValidator.Assistant#createInstance(EClass, EAnnotation) modeled object} in the property tree.
+   * <p>
+   * This implementation always returns <code>true</code>
+   * if {@link org.eclipse.emf.ecore.util.BasicEAnnotationValidator.Assistant#getPropertyClasses(EModelElement)} returns more than one class.
+   * 
+   * @return whether the modeled objects should be explicitly shown in the property tree or should be omitted.
+   * @see EAnnotationItemProvider.SourcePropertyDescriptor#createPropertyValueWrapper(Object, Object)
+   */
+  public boolean isShowInstances(EAnnotation eAnnotation)
+  {
+    return assistant.getPropertyClasses(eAnnotation.getEModelElement()).size() > 1;
+  }
+
+  /**
+   * This creates an adapter for a {@link org.eclipse.emf.ecore.EAnnotation} by calling {@link #doCreateEAnnotationAdapter()}.
+   * Override this to create stateful adapters.
+   * @return the adapter or <code>null</code>.
+   */
+  public Adapter createEAnnotationAdapter()
+  {
+    if (eAnnotationItemProvider == null)
+    {
+      eAnnotationItemProvider = doCreateEAnnotationAdapter();
+    }
+    return eAnnotationItemProvider;
+  }
+
+  /**
+   * Creates the adapter for an {@link EAnnotation}.
+   * Typically this will be a subclass of {@link EAnnotationItemProvider}.
+   * Override this to create stateless adapters.
+   * This implementation always simply creates an EAnnotationItemProvider.
+   * @return the adapter or <code>null</code>.
+   */
+  protected Adapter doCreateEAnnotationAdapter()
+  {
+    return new EAnnotationItemProvider(this);
+  }
+
+  /**
+   * This creates an adapter for a {@link java.util.Map.Entry} by calling {@link #doCreateEStringToStringMapEntryAdapter()}.
+   * Override this to create stateful adapters.
+   * @return the adapter or <code>null</code>.
+   */
+  public Adapter createEStringToStringMapEntryAdapter()
+  {
+    if (eStringToStringMapEntryItemProvider == null)
+    {
+      eStringToStringMapEntryItemProvider = doCreateEStringToStringMapEntryAdapter();
+    }
+    return eStringToStringMapEntryItemProvider;
+  }
+
+  /**
+   * Creates the adapter for an annotation's {@link EAnnotation#getDetails() details}.
+   * Typically this will be a subclass of {@link EStringToStringMapEntryItemProvider}.
+   * Override this to create stateless adapters.
+   * This implementation always simply creates an EStringToStringMapEntryItemProvider.
+   * @return the adapter or <code>null</code>.
+   */
+  protected Adapter doCreateEStringToStringMapEntryAdapter()
+  {
+    return new EStringToStringMapEntryItemProvider(this);
+  }
+
+  /**
+   * This returns the root adapter factory that contains this factory.
+   */
+  public ComposeableAdapterFactory getRootAdapterFactory()
+  {
+    return ecoreItemProviderAdapterFactory.getRootAdapterFactory();
+  }
+
+  /**
+   * This operation is not supported.
+   * A EAnnotationItemProviderAdapterFactory should not be directly composed.
+   * Instead {@link #setParentAdapterFactory(EcoreItemProviderAdapterFactory)} should be called to set the Ecore item provider adapter factory that uses this factory.
+   */
+  public void setParentAdapterFactory(ComposedAdapterFactory parentAdapterFactory)
+  {
+    throw new UnsupportedOperationException("This factory must not be directly a child in a composed adapter factory");
+  }
+
+  /**
+   * Sets the Ecore item provider adapter factory that uses this factory.
+   * @param ecoreItemProviderAdapterFactory the Ecore item provider adapter factory that uses this factory.
+   */
+  public void setParentAdapterFactory(EcoreItemProviderAdapterFactory ecoreItemProviderAdapterFactory)
+  {
+    this.ecoreItemProviderAdapterFactory = ecoreItemProviderAdapterFactory;
+  }
+
+  /**
+   * Returns the resource locator uses by this annotation item provider adapter factory.
+   * @return the resource locator.
+   */
+  public ResourceLocator getResourceLocator()
+  {
+    return resourceLocator;
+  }
+
+  @Override
+  public boolean isFactoryForType(Object type)
+  {
+    return supportedTypes.contains(type) || type == EcorePackage.eINSTANCE;
+  }
+
+  @Override
+  protected Adapter createAdapter(Notifier target)
+  {
+    return modelSwitch.doSwitch((EObject)target);
+  }
+
+  /**
+   * {@inheritDoc}
+   * <p>
+   * This implementation substitutes the factory itself as the key for the adapter.
+   * </p>
+   */
+  @Override
+  public Adapter adapt(Notifier notifier, Object type)
+  {
+    return super.adapt(notifier, this);
+  }
+
+  @Override
+  public Object adapt(Object object, Object type)
+  {
+    if (isFactoryForType(type))
+    {
+      Object adapter = super.adapt(object, type);
+      if (!(type instanceof Class<?>) || (((Class<?>)type).isInstance(adapter)))
+      {
+        return adapter;
+      }
+    }
+
+    return null;
+  }
+
+  /**
+   * {@inheritDoc}
+   * <p>
+   * This implementation also adds the adapter to the {@link #disposable}, if it's an {@link IDisposable}.
+   * </p>
+   */
+  @Override
+  protected void associate(Adapter adapter, Notifier target)
+  {
+    super.associate(adapter, target);
+    if (adapter instanceof IDisposable)
+    {
+      disposable.add(adapter);
+    }
+  }
+
+  /**
+   * This adds a listener.
+   */
+  public void addListener(INotifyChangedListener notifyChangedListener)
+  {
+    changeNotifier.addListener(notifyChangedListener);
+  }
+
+  /**
+   * This removes a listener.
+   */
+  public void removeListener(INotifyChangedListener notifyChangedListener)
+  {
+    changeNotifier.removeListener(notifyChangedListener);
+  }
+
+  /**
+   * This delegates to {@link #changeNotifier} and to {@link #ecoreItemProviderAdapterFactory}.
+   */
+  public void fireNotifyChanged(Notification notification)
+  {
+    changeNotifier.fireNotifyChanged(notification);
+    ecoreItemProviderAdapterFactory.fireNotifyChanged(notification);
+  }
+
+  /**
+   * This disposes all of the item providers created by this factory.
+   */
+  public void dispose()
+  {
+    disposable.dispose();
+  }
+
+  /**
+   * Returns a list of property descriptors for the {@link org.eclipse.emf.ecore.util.BasicEAnnotationValidator.Assistant#createInstance(EClass, EAnnotation) modeled object}
+   * representing the given annotation.
+   * <p>
+   * This implementation uses the {@link org.eclipse.emf.ecore.util.BasicEAnnotationValidator.Assistant#getApplicableProperties(EObject, EAnnotation) applicable properties} of the modeled object,
+   * calling {@link #getPropertyDescriptor(EObject, String, EStructuralFeature, EAnnotation, ResourceLocator) getPropertyDescriptor} to create ach property descriptor.
+   * If that method returns one,
+   * it calls {@link #createPropertyDescriptorDecorator(IItemPropertyDescriptor, EObject, String, EStructuralFeature, EAnnotation, ResourceLocator, EditingDomain) createPropertyDescriptorDecorator} to decorate it,
+   * and then wraps that in a {@link DecategorizingItemPropertyDescritorDecorator}.
+   * This implementation is likely sufficient for most purposes.
+   * </p>
+   * @param eObject the modeled object.
+   * @param eAnnotation the annotation that it models.
+   * @param resourceLocator the resource locator from which to acquire resources.
+   * @return
+   */
+  public List<IItemPropertyDescriptor> getPropertyDescriptors(EObject eObject, EAnnotation eAnnotation, ResourceLocator resourceLocator)
+  {
+    List<IItemPropertyDescriptor> result = new ArrayList<IItemPropertyDescriptor>();
+    EClass eClass = eObject.eClass();
+    Map<String, EStructuralFeature> properties = assistant.getApplicableProperties(eObject, eAnnotation);
+    EList<EStructuralFeature> eAllStructuralFeatures = eClass.getEAllStructuralFeatures();
+    EditingDomain domain = AdapterFactoryEditingDomain.getEditingDomainFor(eAnnotation);
+    for (Map.Entry<String, EStructuralFeature> entry : properties.entrySet())
+    {
+      String key = entry.getKey();
+      EStructuralFeature eStructuralFeature = entry.getValue();
+      if (eAllStructuralFeatures.contains(eStructuralFeature))
+      {
+        IItemPropertyDescriptor propertyDescriptor = getPropertyDescriptor(eObject, key, eStructuralFeature, eAnnotation, resourceLocator);
+        if (propertyDescriptor != null)
+        {
+          IItemPropertyDescriptor decoratedPropertyDescriptor = createPropertyDescriptorDecorator(
+            propertyDescriptor,
+            eObject,
+            key,
+            eStructuralFeature,
+            eAnnotation,
+            resourceLocator,
+            domain);
+          result.add(new DecategorizingItemPropertyDescritorDecorator(eObject, decoratedPropertyDescriptor));
+        }
+      }
+    }
+    return Collections.unmodifiableList(result);
+  }
+
+  /**
+   * Creates a property descriptor for a {@link org.eclipse.emf.ecore.util.BasicEAnnotationValidator.Assistant#getApplicableProperties(EObject, EAnnotation) property} 
+   * of the {@link org.eclipse.emf.ecore.util.BasicEAnnotationValidator.Assistant#createInstance(EClass, EAnnotation) modeled object}
+   * corresponding to the given key and feature for the given annotation.
+   * <p>
+   * This method adapts the object to an {@link IItemPropertySource}, {@link IItemPropertySource#getPropertyDescriptor(Object, Object) fetching} the property descriptor from that, if available.
+   * This implementation is sufficient if the model is generated or if the {@link ReflectiveItemProviderAdapterFactory} is available and provides sufficient support.
+   * </p>
+   * @param eObject the modeled object.
+   * @param key the key of the property.
+   * @param eStructuralFeature the structure feature of the property.
+   * @param eAnnotation the annotation that the modeled object models.
+   * @param resourceLocator the resource locator from which to acquire resources.
+   * @return a property descriptor or <code>null</code>.
+   */
+  public IItemPropertyDescriptor getPropertyDescriptor(EObject eObject, String key, EStructuralFeature eStructuralFeature, EAnnotation eAnnotation, ResourceLocator resourceLocator)
+  {
+    IItemPropertySource itemPropertySource = (IItemPropertySource)getRootAdapterFactory().adapt(eObject, IItemPropertySource.class);
+    return itemPropertySource == null ? null : itemPropertySource.getPropertyDescriptor(eObject, eStructuralFeature);
+  }
+
+  /**
+   * Creates a property descriptor decorator for the property descriptor of a {@link org.eclipse.emf.ecore.util.BasicEAnnotationValidator.Assistant#getApplicableProperties(EObject, EAnnotation) property} 
+   * of the {@link org.eclipse.emf.ecore.util.BasicEAnnotationValidator.Assistant#createInstance(EClass, EAnnotation) modeled object}
+   * corresponding to the given key and feature for the given annotation.
+   * <p>
+   * This implementation creates an instance of {@link ModeledItemPropertyDescriptorDecorator} which uses the assistant to {@link org.eclipse.emf.ecore.util.BasicEAnnotationValidator.Assistant#convertPropertyValueToLiteral(EObject, EStructuralFeature, Object) convert}
+   * the model object's value to a literal.
+   * </p>
+   * @param propertyDescriptor the property descriptor to be decorated.
+   * @param eObject the modeled object.
+   * @param key the key of the property.
+   * @param eStructuralFeature the structure feature of the property.
+   * @param eAnnotation the annotation that the modeled object models.
+   * @param resourceLocator the resource locator from which to acquire resources.
+   * @param domain the editing domain to be used to modify the annotation.
+   * @return a property descriptor or <code>null</code>.
+   */
+  public IItemPropertyDescriptor createPropertyDescriptorDecorator(
+    IItemPropertyDescriptor propertyDescriptor,
+    EObject eObject,
+    String key,
+    EStructuralFeature eStructuralFeature,
+    EAnnotation eAnnotation,
+    ResourceLocator resourceLocator,
+    EditingDomain domain)
+  {
+    return new EAnnotationItemProviderAdapterFactory.ModeledItemPropertyDescriptorDecorator(
+      propertyDescriptor,
+      eObject,
+      key,
+      eStructuralFeature,
+      eAnnotation,
+      resourceLocator,
+      domain,
+      getAssistant());
+  }
+
+  /**
+   * An item property descriptor decorator implementation used by 
+   * {@link EAnnotationItemProviderAdapterFactory#createPropertyDescriptorDecorator(IItemPropertyDescriptor, EObject, String, EStructuralFeature, EAnnotation, ResourceLocator, EditingDomain) EAnnotationItemProviderAdapterFactory.createPropertyDescriptorDecorator}
+   * to create an {@link org.eclipse.emf.ecore.util.BasicEAnnotationValidator.Assistant assistant}-aware decorator.
+   * It is reusable in overrides of EAnnotationItemProviderAdapterFactory.createPropertyDescriptorDecorator.
+   */
+  public static class ModeledItemPropertyDescriptorDecorator extends ItemPropertyDescriptorDecorator
+  {
+    /**
+     * The {@link org.eclipse.emf.ecore.util.BasicEAnnotationValidator.Assistant#getApplicableProperties(EObject, EAnnotation) key} of a property of the modeled object.
+     */
+    protected final String key;
+
+    /**
+     * The {@link org.eclipse.emf.ecore.util.BasicEAnnotationValidator.Assistant#getApplicableProperties(EObject, EAnnotation) feature} of a property of the modeled object.
+     */
+    protected final EStructuralFeature eStructuralFeature;
+
+    /**
+     * The annotation modeled by the modeled object.
+     */
+    protected final EAnnotation eAnnotation;
+
+    /**
+     * The editing domain of the annotation.
+     */
+    protected final EditingDomain domain;
+
+    /**
+     * The assistant used for {@link org.eclipse.emf.ecore.util.BasicEAnnotationValidator.Assistant#convertPropertyValueToLiteral(EObject, EStructuralFeature, Object) value conversion}.
+     */
+    protected final BasicEAnnotationValidator.Assistant assistant;
+
+    public ModeledItemPropertyDescriptorDecorator(
+      IItemPropertyDescriptor propertyDescriptor,
+      EObject eObject,
+      String key,
+      EStructuralFeature eStructuralFeature,
+      EAnnotation eAnnotation,
+      ResourceLocator resourceLocator,
+      EditingDomain domain,
+      BasicEAnnotationValidator.Assistant assistant)
+    {
+      super(eObject, propertyDescriptor);
+      this.key = key;
+      this.eStructuralFeature = eStructuralFeature;
+      this.eAnnotation = eAnnotation;
+      this.domain = domain;
+      this.assistant = assistant;
+    }
+
+    /**
+     * {@inheritDoc}
+     * <p>
+     * This implementation checks whether the resource of the {@link #eAnnotation annotation} is {@link EditingDomain#isReadOnly(Resource) read-only} in {@link #domain}.
+     * </p>
+     */
+    @Override
+    public boolean canSetProperty(Object object)
+    {
+      Resource resource = eAnnotation.eResource();
+      return resource != null && !domain.isReadOnly(resource);
+    }
+
+    /**
+     * {@inheritDoc}
+     * <p>
+     * This implementation checks if the key has a non-null value in the {@link #eAnnotation annotation} details.
+     * </p>
+     */
+    @Override
+    public boolean isPropertySet(Object thisObject)
+    {
+      EMap<String, String> details = eAnnotation.getDetails();
+      return details.get(key) != null;
+    }
+
+    /**
+     * {@inheritDoc}
+     * <p>
+     * This implementation checks if the key has a <code>null</code> value in the {@link #eAnnotation annotation} details and the {@link #getPropertyValue(Object) value of the property} is non-null.
+     * Returning <code>true</code> for this allows the properties view to set the implicit value explicitly via the tool bar button.
+     * </p>
+     */
+    @Override
+    public boolean isPropertyUnsettable(Object object)
+    {
+      EMap<String, String> details = eAnnotation.getDetails();
+      return details.get(key) == null && getPropertyValue(object) != null;
+    }
+
+    /**
+     * {@inheritDoc}
+     * <p>
+     * This implementation removes the detail corresponding to the {@link #key key} from the {@link #eAnnotation annotation}.
+     * </p>
+     */
+    @Override
+    public void resetPropertyValue(Object thisObject)
+    {
+      EMap<String, String> details = eAnnotation.getDetails();
+      for (Map.Entry<String, String> entry : details)
+      {
+        if (key.equals(entry.getKey()))
+        {
+          domain.getCommandStack().execute(RemoveCommand.create(domain, eAnnotation, EcorePackage.Literals.EANNOTATION__DETAILS, entry));
+          return;
+        }
+      }
+    }
+
+    /**
+     * {@inheritDoc}
+     * <p>
+     * This implementation {@link org.eclipse.emf.ecore.util.BasicEAnnotationValidator.Assistant#convertPropertyValueToLiteral(EObject, EStructuralFeature, Object) converts} the value to a literal
+     * and either updates the key's existing entry's value or create a new entry for the key and value.
+     * </p>
+     */
+    @Override
+    public void setPropertyValue(Object object, Object value)
+    {
+      String literal = assistant.convertPropertyValueToLiteral((EObject)this.object, eStructuralFeature, value);
+      EMap<String, String> details = eAnnotation.getDetails();
+      for (Map.Entry<String, String> entry : details)
+      {
+        if (key.equals(entry.getKey()))
+        {
+          // Don't set the literal value if it is the same as the current value.
+          String entryValue = entry.getValue();
+          if (entryValue == null ? literal != null : !entryValue.equals(literal))
+          {
+            domain.getCommandStack().execute(SetCommand.create(domain, entry, EcorePackage.Literals.ESTRING_TO_STRING_MAP_ENTRY__VALUE, literal));
+          }
+          return;
+        }
+      }
+
+      EObject entry = EcoreUtil.create(EcorePackage.Literals.ESTRING_TO_STRING_MAP_ENTRY);
+      entry.eSet(EcorePackage.Literals.ESTRING_TO_STRING_MAP_ENTRY__KEY, key);
+      entry.eSet(EcorePackage.Literals.ESTRING_TO_STRING_MAP_ENTRY__VALUE, literal);
+      domain.getCommandStack().execute(AddCommand.create(domain, eAnnotation, EcorePackage.Literals.EANNOTATION__DETAILS, entry));
+    }
+  }
+
+  /**
+   * A property descriptor created by {@link EAnnotationItemProviderAdapterFactory#getPropertyDescriptors(EObject, EAnnotation, ResourceLocator) EAnnotationItemProviderAdapterFactory#getPropertyDescriptors}
+   * and used by {@link EAnnotationItemProvider.SourcePropertyDescriptor#createPropertyValueWrapper(Object, Object)}.
+   * It specialized {@link #getCategory(Object)} to return null but provides {@link #getCategory()} to give access to the original category.
+   */
+  public final static class DecategorizingItemPropertyDescritorDecorator extends ItemPropertyDescriptorDecorator
+  {
+    /**
+     * Creates an instance.
+     * @param object the object of the property descriptor being decorated.
+     * @param itemPropertyDescriptor the property descriptor to be decorated.
+     */
+    public DecategorizingItemPropertyDescritorDecorator(Object object, IItemPropertyDescriptor itemPropertyDescriptor)
+    {
+      super(object, itemPropertyDescriptor);
+    }
+
+    /**
+     * {@inheritDoc}
+     * <p>
+     * This implementation always returns <code>null</code>.
+     */
+    @Override
+    public String getCategory(Object thisObject)
+    {
+      return null;
+    }
+
+    /**
+     * Returns the group of properties into which this one should be placed based on the underlying property descriptor being decorated.
+     * @return the group of properties into which this one should be placed.
+     */
+    public String getCategory()
+    {
+      return super.getCategory(this.object);
+    }
+  }
+
+  /**
+   * A convenient implementation of a property source with an explicit list of property descriptors that can be {@link #add(IItemPropertyDescriptor) populated} after construction.
+   */
+  public static final class Group implements IItemPropertySource
+  {
+    /**
+     * The {@link #getEditableValue(Object) value} for this property source.
+     */
+    protected Object propertyValue;
+
+    /**
+     * The list of property descriptors as returned by {@link #getPropertyDescriptors()}.
+     */
+    protected final List<IItemPropertyDescriptor> itemPropertyDescriptors = new ArrayList<IItemPropertyDescriptor>();;
+
+    /**
+     * Creates an instance that wraps the given property value.
+     * @param propertyValue the {@link #getEditableValue(Object) value} for this property source.
+     */
+    public Group(Object propertyValue)
+    {
+      this.propertyValue = propertyValue;
+    }
+
+    /**
+     * Adds the given property descriptor to the {@link #getPropertyDescriptors() property descriptors}.
+     * @param propertyDescriptor the property descriptor to add.
+     */
+    public void add(IItemPropertyDescriptor propertyDescriptor)
+    {
+      itemPropertyDescriptors.add(propertyDescriptor);
+    }
+
+    /**
+     * {@inheritDoc}
+     * <p>
+     * This implementation simply delegates to {@link #getPropertyDescriptors()}.
+     * </p>
+     */
+    public List<IItemPropertyDescriptor> getPropertyDescriptors(Object object)
+    {
+      return itemPropertyDescriptors;
+    }
+
+    /**
+     * Returns the underlying list of property descriptors.
+     * This list can be directly modified by the caller.
+     * @return the underlying list of property descriptors.
+     */
+    public List<IItemPropertyDescriptor> getPropertyDescriptors()
+    {
+      return itemPropertyDescriptors;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public IItemPropertyDescriptor getPropertyDescriptor(Object object, Object propertyID)
+    {
+      for (IItemPropertyDescriptor itemPropertyDescriptor : getPropertyDescriptors(object))
+      {
+        if (propertyID.equals(itemPropertyDescriptor.getId(object)) || propertyID.equals(itemPropertyDescriptor.getFeature(object)))
+        {
+          return itemPropertyDescriptor;
+        }
+      }
+      return null;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Object getEditableValue(Object object)
+    {
+      return propertyValue;
+    }
+  }
+}
diff --git a/plugins/org.eclipse.emf.ecore.edit/src/org/eclipse/emf/ecore/provider/annotation/EcoreAnnotationItemProviderAdapterFactory.java b/plugins/org.eclipse.emf.ecore.edit/src/org/eclipse/emf/ecore/provider/annotation/EcoreAnnotationItemProviderAdapterFactory.java
new file mode 100644
index 0000000..fd0b8c4
--- /dev/null
+++ b/plugins/org.eclipse.emf.ecore.edit/src/org/eclipse/emf/ecore/provider/annotation/EcoreAnnotationItemProviderAdapterFactory.java
@@ -0,0 +1,123 @@
+/**
+ * Copyright (c) Eclipse contributors and others.
+ * All rights reserved.   This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.eclipse.emf.ecore.provider.annotation;
+
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.emf.common.util.ResourceLocator;
+import org.eclipse.emf.common.util.UniqueEList;
+import org.eclipse.emf.ecore.EAnnotation;
+import org.eclipse.emf.ecore.EAnnotationValidator;
+import org.eclipse.emf.ecore.EAttribute;
+import org.eclipse.emf.ecore.EDataType;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EOperation;
+import org.eclipse.emf.ecore.EStructuralFeature;
+import org.eclipse.emf.ecore.EValidator;
+import org.eclipse.emf.ecore.EcorePackage;
+import org.eclipse.emf.ecore.provider.EcoreEditPlugin;
+import org.eclipse.emf.ecore.util.BasicEAnnotationValidator;
+import org.eclipse.emf.edit.provider.IItemPropertyDescriptor;
+import org.eclipse.emf.edit.provider.ItemPropertyDescriptor;
+
+
+/**
+ * An extension for annotations with source <code>http://www.eclipse.org/emf/2002/Ecore</code>.
+ *
+ * @see EcorePackage#eNS_URI
+ *
+ * @since 2.14
+ */
+public final class EcoreAnnotationItemProviderAdapterFactory extends EAnnotationItemProviderAdapterFactory
+{
+  protected static final BasicEAnnotationValidator.Assistant ASSISTANT = ((BasicEAnnotationValidator)EAnnotationValidator.Registry.INSTANCE.getEAnnotationValidator(
+    EcorePackage.eNS_URI)).getAssistant();
+
+  /**
+   * Creates an instance.
+   */
+  public EcoreAnnotationItemProviderAdapterFactory()
+  {
+    super(EcoreEditPlugin.INSTANCE, ASSISTANT);
+
+    //    // This can be used to test a registered validator designed to validate annotations on annotations.
+    //    int xxx;
+    //    final BasicEAnnotationValidator.Assistant assistant = ((BasicEAnnotationValidator)EAnnotationValidator.Registry.INSTANCE.getEAnnotationValidator("Testing")).getAssistant();
+    //    EAnnotationItemProviderAdapterFactory.Registry.INSTANCE.put("Testing", new EAnnotationItemProviderAdapterFactory.Factory()
+    //      {
+    //        public EAnnotationItemProviderAdapterFactory createEAnnotationItemProviderAdapterFactory()
+    //        {
+    //          return new EAnnotationItemProviderAdapterFactory(EcoreEditPlugin.INSTANCE, assistant)
+    //            {
+    //            };
+    //        }
+    //      });
+  }
+
+  @Override
+  public IItemPropertyDescriptor getPropertyDescriptor(EObject eObject, String key, EStructuralFeature eStructuralFeature, EAnnotation eAnnotation, ResourceLocator resourceLocator)
+  {
+    EAttribute eAttribute = (EAttribute)eStructuralFeature;
+    String messageKey = eAttribute.getEContainingClass().getName() + "_" + eAttribute.getName();
+    return new ItemPropertyDescriptor(
+      getRootAdapterFactory(),
+      resourceLocator.getString("_UI_" + messageKey + "_feature"),
+      resourceLocator.getString("_UI_" + messageKey + "_description"),
+      eAttribute,
+      eAttribute.isChangeable(),
+      ItemPropertyDescriptor.GENERIC_VALUE_IMAGE)
+      {
+        @Override
+        public Collection<?> getChoiceOfValues(Object object)
+        {
+          String name = feature.getName();
+          if (name.equals("conversionDelegates"))
+          {
+            return mergeValueChoices(object, EDataType.Internal.ConversionDelegate.Factory.Registry.INSTANCE.keySet());
+          }
+          else if (name.equals("invocationDelegates"))
+          {
+            return mergeValueChoices(object, EOperation.Internal.InvocationDelegate.Factory.Registry.INSTANCE.keySet());
+          }
+          else if (name.equals("validationDelegates"))
+          {
+            return mergeValueChoices(object, EValidator.ValidationDelegate.Registry.INSTANCE.keySet());
+          }
+          else if (name.equals("settingDelegates"))
+          {
+            return mergeValueChoices(object, EStructuralFeature.Internal.SettingDelegate.Factory.Registry.INSTANCE.keySet());
+          }
+          else
+          {
+            return super.getChoiceOfValues(object);
+          }
+        }
+
+        @Override
+        public boolean isChoiceArbitrary(Object object)
+        {
+          String name = feature.getName();
+          return super.isChoiceArbitrary(object) || name.equals("conversionDelegates") || name.equals("invocationDelegates") || name.equals("validationDelegates")
+            || name.equals("settingDelegates");
+        }
+
+        private Collection<String> mergeValueChoices(Object object, Set<String> keys)
+        {
+          EObject eObject = (EObject)object;
+          @SuppressWarnings("unchecked")
+          List<String> values = (List<String>)eObject.eGet(feature);
+          List<String> result = new UniqueEList<String>(values);
+          result.addAll(keys);
+          return result;
+        }
+      };
+  }
+}
diff --git a/plugins/org.eclipse.emf.ecore.edit/src/org/eclipse/emf/ecore/provider/annotation/ExtendedMetaDataAnnotationItemProviderAdapterFactory.java b/plugins/org.eclipse.emf.ecore.edit/src/org/eclipse/emf/ecore/provider/annotation/ExtendedMetaDataAnnotationItemProviderAdapterFactory.java
new file mode 100644
index 0000000..703c2c3
--- /dev/null
+++ b/plugins/org.eclipse.emf.ecore.edit/src/org/eclipse/emf/ecore/provider/annotation/ExtendedMetaDataAnnotationItemProviderAdapterFactory.java
@@ -0,0 +1,320 @@
+/**
+ * Copyright (c) Eclipse contributors and others.
+ * All rights reserved.   This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.eclipse.emf.ecore.provider.annotation;
+
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.emf.common.command.Command;
+import org.eclipse.emf.common.notify.Notifier;
+import org.eclipse.emf.common.util.EList;
+import org.eclipse.emf.common.util.EMap;
+import org.eclipse.emf.common.util.ResourceLocator;
+import org.eclipse.emf.ecore.EAnnotation;
+import org.eclipse.emf.ecore.EAnnotationValidator;
+import org.eclipse.emf.ecore.EClassifier;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EPackage;
+import org.eclipse.emf.ecore.EReference;
+import org.eclipse.emf.ecore.EStructuralFeature;
+import org.eclipse.emf.ecore.EcorePackage;
+import org.eclipse.emf.ecore.provider.EcoreEditPlugin;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.emf.ecore.resource.ResourceSet;
+import org.eclipse.emf.ecore.util.BasicEAnnotationValidator;
+import org.eclipse.emf.ecore.util.EcoreUtil;
+import org.eclipse.emf.ecore.util.ExtendedMetaData;
+import org.eclipse.emf.ecore.util.ExtendedMetaDataAnnotationValidator;
+import org.eclipse.emf.edit.command.ChangeCommand;
+import org.eclipse.emf.edit.domain.EditingDomain;
+import org.eclipse.emf.edit.provider.IItemPropertyDescriptor;
+import org.eclipse.emf.edit.provider.ItemPropertyDescriptor;
+import org.eclipse.emf.edit.provider.ItemPropertyDescriptorDecorator;
+
+
+/**
+ * An extension for annotations with source <code>http:///org/eclipse/emf/ecore/util/ExtendedMetaData</code>.
+ *
+ * @see ExtendedMetaData#ANNOTATION_URI
+ *
+ * @since 2.14
+ */
+public final class ExtendedMetaDataAnnotationItemProviderAdapterFactory extends EAnnotationItemProviderAdapterFactory
+{
+  protected static final BasicEAnnotationValidator.Assistant ASSISTANT = ((BasicEAnnotationValidator)EAnnotationValidator.Registry.INSTANCE.getEAnnotationValidator(
+    ExtendedMetaData.ANNOTATION_URI)).getAssistant();
+
+  /**
+   * Creates an instance.
+   */
+  public ExtendedMetaDataAnnotationItemProviderAdapterFactory()
+  {
+    super(EcoreEditPlugin.INSTANCE, ASSISTANT);
+  }
+
+  @Override
+  public IItemPropertyDescriptor getPropertyDescriptor(EObject eObject, String key, EStructuralFeature eStructuralFeature, EAnnotation eAnnotation, ResourceLocator resourceLocator)
+  {
+    final EObject context = eObject;
+    String messageKey = eStructuralFeature.getEContainingClass().getName() + "_" + eStructuralFeature.getName();
+    return new ItemPropertyDescriptor(
+      getRootAdapterFactory(),
+      resourceLocator,
+      resourceLocator.getString("_UI_" + messageKey + "_feature"),
+      resourceLocator.getString("_UI_" + messageKey + "_description"),
+      eStructuralFeature,
+      eStructuralFeature.isChangeable(),
+      false,
+      true,
+      ItemPropertyDescriptor.GENERIC_VALUE_IMAGE,
+      null,
+      null)
+      {
+        @Override
+        public Collection<?> getChoiceOfValues(Object object)
+        {
+          EObject eObject = (EObject)object;
+          if (feature instanceof EReference)
+          {
+            EClassifier eType = feature.getEType();
+            if (eType == null)
+            {
+              return null;
+            }
+            else
+            {
+              Collection<EObject> result = getReachableObjectsOfType(context, eType);
+              if (!feature.isMany())
+              {
+                result.add(null);
+              }
+              return ExtendedMetaDataAnnotationValidator.INSTANCE.filterChoiceOfValues(eObject, feature, result);
+            }
+          }
+          else if ("namespace".equals(feature.getName()))
+          {
+            Collection<EObject> result = getReachableObjectsOfType(context, EcorePackage.Literals.EPACKAGE);
+            List<EObject> eObjects = new LinkedList<EObject>(result);
+            Resource resource = context.eResource();
+            if (resource != null)
+            {
+              ResourceSet resourceSet = resource.getResourceSet();
+              if (resourceSet != null)
+              {
+                Collection<EObject> visited = new HashSet<EObject>(eObjects);
+                EPackage.Registry packageRegistry = resourceSet.getPackageRegistry();
+                for (String nsURI : packageRegistry.keySet())
+                {
+                  collectReachableObjectsOfType(visited, eObjects, packageRegistry.getEPackage(nsURI), EcorePackage.Literals.EPACKAGE);
+                }
+              }
+            }
+            return ExtendedMetaDataAnnotationValidator.INSTANCE.filterChoiceOfValues(eObject, feature, eObjects);
+          }
+          else if ("wildcards".equals(feature.getName()))
+          {
+            Collection<EObject> ePackages = getReachableObjectsOfType(context, EcorePackage.Literals.EPACKAGE);
+            List<EObject> eObjects = new LinkedList<EObject>(ePackages);
+            Resource resource = context.eResource();
+            if (resource != null)
+            {
+              ResourceSet resourceSet = resource.getResourceSet();
+              if (resourceSet != null)
+              {
+                Collection<EObject> visited = new HashSet<EObject>(eObjects);
+                EPackage.Registry packageRegistry = resourceSet.getPackageRegistry();
+                for (String nsURI : packageRegistry.keySet())
+                {
+                  collectReachableObjectsOfType(visited, eObjects, packageRegistry.getEPackage(nsURI), EcorePackage.Literals.EPACKAGE);
+                }
+              }
+            }
+            return ExtendedMetaDataAnnotationValidator.INSTANCE.filterChoiceOfValues(eObject, feature, eObjects);
+          }
+          else
+          {
+            return ExtendedMetaDataAnnotationValidator.INSTANCE.filterChoiceOfValues(eObject, feature, super.getChoiceOfValues(object));
+          }
+        }
+
+        @Override
+        public boolean isChoiceArbitrary(Object object)
+        {
+          String name = feature.getName();
+          return "namespace".equals(name) || "wildcards".equals(name);
+        }
+      };
+  }
+
+  @Override
+  public IItemPropertyDescriptor createPropertyDescriptorDecorator(
+    IItemPropertyDescriptor propertyDescriptor,
+    EObject eObject,
+    String key,
+    EStructuralFeature eStructuralFeature,
+    EAnnotation eAnnotation,
+    ResourceLocator resourceLocator,
+    EditingDomain domain)
+  {
+    return new ValuePropertyDescriptorDecorator(domain, eObject, propertyDescriptor, eAnnotation);
+  }
+
+  private static class ValuePropertyDescriptorDecorator extends ItemPropertyDescriptorDecorator
+  {
+    private final EAnnotation eAnnotation;
+
+    private EditingDomain domain;
+
+    private ValuePropertyDescriptorDecorator(EditingDomain domain, Object object, IItemPropertyDescriptor itemPropertyDescriptor, EAnnotation eAnnotation)
+    {
+      super(object, itemPropertyDescriptor);
+      this.domain = domain;
+      this.eAnnotation = eAnnotation;
+    }
+
+    @Override
+    public boolean isPropertyUnsettable(Object object)
+    {
+      return "name".equals(itemPropertyDescriptor.getId(object));
+    }
+
+    public void basicSetPropertyValue(Object object, Object value)
+    {
+      super.setPropertyValue(object, value);
+    }
+
+    public void basicResetPropertyValue(Object object)
+    {
+      super.resetPropertyValue(object);
+    }
+
+    @Override
+    public void resetPropertyValue(Object object)
+    {
+      Command command = new ValueChangeCommand(EcoreUtil.getRootContainer(eAnnotation), object, null);
+      domain.getCommandStack().execute(command);
+    }
+
+    @Override
+    public void setPropertyValue(Object object, Object value)
+    {
+      if ("".equals(value))
+      {
+        String id = itemPropertyDescriptor.getId(object);
+        if ("minInclusive".equals(id) || "maxInclusive".equals(id) || "minExclusive".equals(id) || "maxExclusive".equals(id))
+        {
+          return;
+        }
+      }
+
+      Command command = new ValueChangeCommand(EcoreUtil.getRootContainer(eAnnotation), object, value);
+      domain.getCommandStack().execute(command);
+    }
+
+    protected class ValueChangeCommand extends ChangeCommand
+    {
+      private final Object object;
+
+      private final Object value;
+
+      private ValueChangeCommand(Notifier notifier, Object object, Object value)
+      {
+        super(notifier);
+        this.object = object;
+        this.value = value;
+      }
+
+      @Override
+      protected void doExecute()
+      {
+        List<Map.Entry<String, String>> originalPrecedingDetails = null;
+        EMap<String, String> details = eAnnotation.getDetails();
+        if (object instanceof Map.Entry<?, ?>)
+        {
+          originalPrecedingDetails = new ArrayList<Map.Entry<String, String>>();
+          for (Map.Entry<String, String> entry : details)
+          {
+            if (entry == object)
+            {
+              break;
+            }
+            else
+            {
+              originalPrecedingDetails.add(entry);
+            }
+          }
+        }
+
+        if (value == null)
+        {
+          basicResetPropertyValue(object);
+        }
+        else
+        {
+          basicSetPropertyValue(object, value);
+        }
+
+        if (originalPrecedingDetails != null && !details.contains(object))
+        {
+          @SuppressWarnings("unchecked")
+          Map.Entry<String, String> entry = (Map.Entry<String, String>)object;
+          boolean added = false;
+          for (int i = 0, size = details.size(); i < size; i++)
+          {
+            if (!originalPrecedingDetails.contains(details.get(i)))
+            {
+              details.add(i, entry);
+              added = true;
+              break;
+            }
+          }
+          if (!added)
+          {
+            details.add(entry);
+          }
+          entry.setValue(value == null ? null : value.toString());
+        }
+      }
+
+      @Override
+      public String getLabel()
+      {
+        return EcoreEditPlugin.INSTANCE.getString("_UI_ChangeExtendedMetaData_text");
+      }
+
+      @Override
+      public String getDescription()
+      {
+        return EcoreEditPlugin.INSTANCE.getString("_UI_ChangeExtendedMetaData_description");
+      }
+
+      @Override
+      public Collection<?> getAffectedObjects()
+      {
+        if (changeDescription != null)
+        {
+          EList<EObject> objectsToDetach = changeDescription.getObjectsToDetach();
+          if (!objectsToDetach.isEmpty())
+          {
+            return objectsToDetach;
+          }
+          return changeDescription.getObjectChanges().keySet();
+        }
+        else
+        {
+          return super.getAffectedObjects();
+        }
+      }
+    }
+  }
+}
diff --git a/plugins/org.eclipse.emf.ecore.xcore.ui/src/org/eclipse/emf/ecore/xcore/ui/XcoreUiModule.java b/plugins/org.eclipse.emf.ecore.xcore.ui/src/org/eclipse/emf/ecore/xcore/ui/XcoreUiModule.java
index 7d23854..c5a67c8 100644
--- a/plugins/org.eclipse.emf.ecore.xcore.ui/src/org/eclipse/emf/ecore/xcore/ui/XcoreUiModule.java
+++ b/plugins/org.eclipse.emf.ecore.xcore.ui/src/org/eclipse/emf/ecore/xcore/ui/XcoreUiModule.java
@@ -111,6 +111,7 @@
     return XcoreJavaProjectProvider.class;
   }
 
+  @Override
   public Class<?extends EclipseResourceFileSystemAccess2> bindEclipseResourceFileSystemAccess2()
   {
     return XcoreFileSystemAccess.class;
diff --git a/plugins/org.eclipse.emf.ecore.xcore/src/org/eclipse/emf/ecore/xcore/XcoreRuntimeModule.java b/plugins/org.eclipse.emf.ecore.xcore/src/org/eclipse/emf/ecore/xcore/XcoreRuntimeModule.java
index cd741c0..2d313aa 100644
--- a/plugins/org.eclipse.emf.ecore.xcore/src/org/eclipse/emf/ecore/xcore/XcoreRuntimeModule.java
+++ b/plugins/org.eclipse.emf.ecore.xcore/src/org/eclipse/emf/ecore/xcore/XcoreRuntimeModule.java
@@ -229,7 +229,8 @@
   {
     return XcoreReferenceFinder.class;
   }
-  
+
+  @Override
   public Class<? extends ILinkingDiagnosticMessageProvider> bindILinkingDiagnosticMessageProvider() 
   {
     return XcoreAwareMessageProvider.class;
diff --git a/plugins/org.eclipse.emf.ecore.xcore/src/org/eclipse/emf/ecore/xcore/findrefs/XcoreReferenceFinder.java b/plugins/org.eclipse.emf.ecore.xcore/src/org/eclipse/emf/ecore/xcore/findrefs/XcoreReferenceFinder.java
index 54eeaf5..d0d50fa 100644
--- a/plugins/org.eclipse.emf.ecore.xcore/src/org/eclipse/emf/ecore/xcore/findrefs/XcoreReferenceFinder.java
+++ b/plugins/org.eclipse.emf.ecore.xcore/src/org/eclipse/emf/ecore/xcore/findrefs/XcoreReferenceFinder.java
@@ -31,6 +31,7 @@
   * 
   * Xtext 2.10.x
   */
+  @Override
   protected void findLocalReferencesFromElement(Predicate<URI> targetURIs, EObject sourceCandidate, Resource localResource,
       Acceptor acceptor)
   {
diff --git a/plugins/org.eclipse.emf.ecore.xcore/src/org/eclipse/emf/ecore/xcore/formatting/XcoreFormatterPreferenceValuesProvider.java b/plugins/org.eclipse.emf.ecore.xcore/src/org/eclipse/emf/ecore/xcore/formatting/XcoreFormatterPreferenceValuesProvider.java
index 7e0dac7..97de84c 100644
--- a/plugins/org.eclipse.emf.ecore.xcore/src/org/eclipse/emf/ecore/xcore/formatting/XcoreFormatterPreferenceValuesProvider.java
+++ b/plugins/org.eclipse.emf.ecore.xcore/src/org/eclipse/emf/ecore/xcore/formatting/XcoreFormatterPreferenceValuesProvider.java
@@ -29,6 +29,7 @@
   @Inject 
   private IPreferenceValuesProvider valuesProvider;
 
+  @Override
   public IPreferenceValues getPreferenceValues(Resource resource)
   {
     final IPreferenceValues preferenceValues = internalGetRawPreferenceValues(resource);
@@ -62,6 +63,7 @@
       };
   }
 
+  @Override
   protected IPreferenceValues internalGetRawPreferenceValues(final Resource resource)
   {
     return valuesProvider.getPreferenceValues(resource);
diff --git a/plugins/org.eclipse.emf.ecore.xcore/src/org/eclipse/emf/ecore/xcore/interpreter/XcoreInterpreter.java b/plugins/org.eclipse.emf.ecore.xcore/src/org/eclipse/emf/ecore/xcore/interpreter/XcoreInterpreter.java
index 25fccce..1472b7a 100644
--- a/plugins/org.eclipse.emf.ecore.xcore/src/org/eclipse/emf/ecore/xcore/interpreter/XcoreInterpreter.java
+++ b/plugins/org.eclipse.emf.ecore.xcore/src/org/eclipse/emf/ecore/xcore/interpreter/XcoreInterpreter.java
@@ -112,6 +112,7 @@
     return super.featureCallField(jvmField, receiver);
   }
 
+  @Override
   protected Object _doEvaluate(XInstanceOfExpression instanceOf, IEvaluationContext context, CancelIndicator indicator)
   {
     ToXcoreMapping mapping = mapper.getToXcoreMapping(instanceOf.getType().getType());
@@ -128,6 +129,7 @@
     }
   }
 
+  @Override
   protected Object _doEvaluate(XCastedExpression castedExpression, IEvaluationContext context, CancelIndicator indicator)
   {
     JvmType castType = castedExpression.getType().getType();
diff --git a/plugins/org.eclipse.emf.ecore.xmi/src/org/eclipse/emf/ecore/xmi/impl/EcoreResourceFactoryImpl.java b/plugins/org.eclipse.emf.ecore.xmi/src/org/eclipse/emf/ecore/xmi/impl/EcoreResourceFactoryImpl.java
index 6b6f190..efa6201 100644
--- a/plugins/org.eclipse.emf.ecore.xmi/src/org/eclipse/emf/ecore/xmi/impl/EcoreResourceFactoryImpl.java
+++ b/plugins/org.eclipse.emf.ecore.xmi/src/org/eclipse/emf/ecore/xmi/impl/EcoreResourceFactoryImpl.java
@@ -41,6 +41,11 @@
       };
     result.setEncoding("UTF-8");
 
+    if ("genmodel".equals(uri.fileExtension()))
+    {
+      result.getDefaultLoadOptions().put(XMLResource.OPTION_RECORD_UNKNOWN_FEATURE, Boolean.TRUE);
+    }
+
     result.getDefaultSaveOptions().put(XMLResource.OPTION_USE_ENCODED_ATTRIBUTE_STYLE, Boolean.TRUE);
     result.getDefaultSaveOptions().put(XMLResource.OPTION_LINE_WIDTH, 80);
     result.getDefaultSaveOptions().put(XMLResource.OPTION_URI_HANDLER, new URIHandlerImpl.PlatformSchemeAware());
diff --git a/plugins/org.eclipse.emf.ecore/model/Ecore.ecore b/plugins/org.eclipse.emf.ecore/model/Ecore.ecore
index 15a3569..37fcafa 100644
--- a/plugins/org.eclipse.emf.ecore/model/Ecore.ecore
+++ b/plugins/org.eclipse.emf.ecore/model/Ecore.ecore
@@ -11,7 +11,7 @@
   </eClassifiers>
   <eClassifiers xsi:type="ecore:EClass" name="EAnnotation" eSuperTypes="#//EModelElement">
     <eAnnotations source="http://www.eclipse.org/emf/2002/Ecore">
-      <details key="constraints" value="WellFormedSourceURI"/>
+      <details key="constraints" value="WellFormed WellFormedSourceURI"/>
     </eAnnotations>
     <eStructuralFeatures xsi:type="ecore:EAttribute" name="source" eType="#//EString"/>
     <eStructuralFeatures xsi:type="ecore:EReference" name="details" upperBound="-1"
diff --git a/plugins/org.eclipse.emf.ecore/model/Ecore.genmodel b/plugins/org.eclipse.emf.ecore/model/Ecore.genmodel
index 1bd37ba..9b55b31 100644
--- a/plugins/org.eclipse.emf.ecore/model/Ecore.genmodel
+++ b/plugins/org.eclipse.emf.ecore/model/Ecore.genmodel
@@ -4,7 +4,8 @@
     runtimeJar="true" modelName="Ecore" updateClasspath="false" testsDirectory=""
     booleanFlagsField="eFlags" booleanFlagsReservedBits="8" importerID="org.eclipse.emf.importer.ecore"
     containmentProxies="true" minimalReflectiveMethods="false" complianceLevel="5.0"
-    language="en" operationReflection="true" decoration="Live" oSGiCompatible="true">
+    language="en" operationReflection="true" decoration="Live" oSGiCompatible="true"
+    eclipsePlatformVersion="Juno">
   <genAnnotations source="http://www.eclipse.org/emf/2002/GenModel/exporter/org.eclipse.xsd.ecore.exporter">
     <genAnnotations source="selectedPackages">
       <details key="http://www.eclipse.org/emf/2002/Ecore" value="Ecore.xsd"/>
diff --git a/plugins/org.eclipse.emf.ecore/model/ExtendedMetaData.ecore b/plugins/org.eclipse.emf.ecore/model/ExtendedMetaData.ecore
new file mode 100644
index 0000000..cdf4f9c
--- /dev/null
+++ b/plugins/org.eclipse.emf.ecore/model/ExtendedMetaData.ecore
@@ -0,0 +1,199 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ecore:EPackage xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" name="data" nsURI="http:///org/eclipse/emf/ecore/util/ExtendedMetaData"
+    nsPrefix="data">
+  <eClassifiers xsi:type="ecore:EClass" name="Package">
+    <eStructuralFeatures xsi:type="ecore:EAttribute" name="qualified" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EBoolean"
+        transient="true">
+      <eAnnotations source="Reflection">
+        <details key="accessor" value="Qualified"/>
+      </eAnnotations>
+    </eStructuralFeatures>
+  </eClassifiers>
+  <eClassifiers xsi:type="ecore:EClass" name="Class" eSuperTypes="#//Classifier">
+    <eStructuralFeatures xsi:type="ecore:EAttribute" name="documentRoot" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EBoolean"
+        derived="true">
+      <eAnnotations source="Reflection">
+        <details key="accessor" value="DocumentRoot"/>
+      </eAnnotations>
+    </eStructuralFeatures>
+    <eStructuralFeatures xsi:type="ecore:EAttribute" name="kind" eType="#//ContentKind">
+      <eAnnotations source="Reflection">
+        <details key="accessor" value="ContentKind"/>
+      </eAnnotations>
+    </eStructuralFeatures>
+  </eClassifiers>
+  <eClassifiers xsi:type="ecore:EClass" name="DataType" eSuperTypes="#//Classifier">
+    <eStructuralFeatures xsi:type="ecore:EReference" name="baseType" eType="ecore:EClass http://www.eclipse.org/emf/2002/Ecore#//EDataType">
+      <eAnnotations source="Reflection">
+        <details key="accessor" value="BaseType"/>
+      </eAnnotations>
+    </eStructuralFeatures>
+    <eStructuralFeatures xsi:type="ecore:EReference" name="itemType" eType="ecore:EClass http://www.eclipse.org/emf/2002/Ecore#//EDataType">
+      <eAnnotations source="Reflection">
+        <details key="accessor" value="ItemType"/>
+      </eAnnotations>
+    </eStructuralFeatures>
+    <eStructuralFeatures xsi:type="ecore:EReference" name="memberTypes" upperBound="-1"
+        eType="ecore:EClass http://www.eclipse.org/emf/2002/Ecore#//EDataType">
+      <eAnnotations source="Reflection">
+        <details key="accessor" value="MemberTypes"/>
+      </eAnnotations>
+    </eStructuralFeatures>
+    <eStructuralFeatures xsi:type="ecore:EAttribute" name="whiteSpace" eType="#//WhiteSpaceKind">
+      <eAnnotations source="Reflection">
+        <details key="accessor" value="WhiteSpaceFacet"/>
+      </eAnnotations>
+    </eStructuralFeatures>
+    <eStructuralFeatures xsi:type="ecore:EAttribute" name="enumeration" upperBound="-1"
+        eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString">
+      <eAnnotations source="Reflection">
+        <details key="accessor" value="EnumerationFacet"/>
+      </eAnnotations>
+    </eStructuralFeatures>
+    <eStructuralFeatures xsi:type="ecore:EAttribute" name="pattern" upperBound="-1"
+        eType="#//Pattern">
+      <eAnnotations source="Reflection">
+        <details key="accessor" value="PatternFacet"/>
+      </eAnnotations>
+    </eStructuralFeatures>
+    <eStructuralFeatures xsi:type="ecore:EAttribute" name="totalDigits" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EInt">
+      <eAnnotations source="Reflection">
+        <details key="accessor" value="TotalDigitsFacet"/>
+      </eAnnotations>
+    </eStructuralFeatures>
+    <eStructuralFeatures xsi:type="ecore:EAttribute" name="fractionDigits" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EInt">
+      <eAnnotations source="Reflection">
+        <details key="accessor" value="FractionDigitsFacet"/>
+      </eAnnotations>
+    </eStructuralFeatures>
+    <eStructuralFeatures xsi:type="ecore:EAttribute" name="length" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EInt">
+      <eAnnotations source="Reflection">
+        <details key="accessor" value="LengthFacet"/>
+      </eAnnotations>
+    </eStructuralFeatures>
+    <eStructuralFeatures xsi:type="ecore:EAttribute" name="minLength" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EInt">
+      <eAnnotations source="Reflection">
+        <details key="accessor" value="MinLengthFacet"/>
+      </eAnnotations>
+    </eStructuralFeatures>
+    <eStructuralFeatures xsi:type="ecore:EAttribute" name="maxLength" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EInt">
+      <eAnnotations source="Reflection">
+        <details key="accessor" value="MaxLengthFacet"/>
+      </eAnnotations>
+    </eStructuralFeatures>
+    <eStructuralFeatures xsi:type="ecore:EAttribute" name="minExclusive" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString">
+      <eAnnotations source="Reflection">
+        <details key="accessor" value="MinExclusiveFacet"/>
+      </eAnnotations>
+    </eStructuralFeatures>
+    <eStructuralFeatures xsi:type="ecore:EAttribute" name="maxExclusive" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString">
+      <eAnnotations source="Reflection">
+        <details key="accessor" value="MaxExclusiveFacet"/>
+      </eAnnotations>
+    </eStructuralFeatures>
+    <eStructuralFeatures xsi:type="ecore:EAttribute" name="minInclusive" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString">
+      <eAnnotations source="Reflection">
+        <details key="accessor" value="MinInclusiveFacet"/>
+      </eAnnotations>
+    </eStructuralFeatures>
+    <eStructuralFeatures xsi:type="ecore:EAttribute" name="maxInclusive" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString">
+      <eAnnotations source="Reflection">
+        <details key="accessor" value="MaxInclusiveFacet"/>
+      </eAnnotations>
+    </eStructuralFeatures>
+  </eClassifiers>
+  <eClassifiers xsi:type="ecore:EClass" name="StructuralFeature">
+    <eStructuralFeatures xsi:type="ecore:EAttribute" name="namespace" eType="#//XMLNamespace">
+      <eAnnotations source="Reflection">
+        <details key="accessor" value="Namespace"/>
+      </eAnnotations>
+    </eStructuralFeatures>
+    <eStructuralFeatures xsi:type="ecore:EAttribute" name="name" eType="#//XMLName">
+      <eAnnotations source="Reflection">
+        <details key="accessor" value="Name"/>
+      </eAnnotations>
+    </eStructuralFeatures>
+    <eStructuralFeatures xsi:type="ecore:EAttribute" name="kind" eType="#//FeatureKind">
+      <eAnnotations source="Reflection">
+        <details key="accessor" value="FeatureKind"/>
+      </eAnnotations>
+    </eStructuralFeatures>
+    <eStructuralFeatures xsi:type="ecore:EAttribute" name="wildcards" upperBound="-1"
+        eType="#//Wildcard">
+      <eAnnotations source="Reflection">
+        <details key="accessor" value="Wildcards"/>
+      </eAnnotations>
+    </eStructuralFeatures>
+    <eStructuralFeatures xsi:type="ecore:EAttribute" name="processing" eType="#//ProcessingKind">
+      <eAnnotations source="Reflection">
+        <details key="accessor" value="ProcessingKind"/>
+      </eAnnotations>
+    </eStructuralFeatures>
+    <eStructuralFeatures xsi:type="ecore:EReference" name="group" eType="ecore:EClass http://www.eclipse.org/emf/2002/Ecore#//EStructuralFeature">
+      <eAnnotations source="Reflection">
+        <details key="accessor" value="Group"/>
+      </eAnnotations>
+    </eStructuralFeatures>
+    <eStructuralFeatures xsi:type="ecore:EReference" name="affiliation" eType="ecore:EClass http://www.eclipse.org/emf/2002/Ecore#//EStructuralFeature">
+      <eAnnotations source="Reflection">
+        <details key="accessor" value="Affiliation"/>
+      </eAnnotations>
+    </eStructuralFeatures>
+  </eClassifiers>
+  <eClassifiers xsi:type="ecore:EClass" name="Classifier" abstract="true">
+    <eStructuralFeatures xsi:type="ecore:EAttribute" name="name" eType="#//XMLName">
+      <eAnnotations source="Reflection">
+        <details key="accessor" value="Name"/>
+      </eAnnotations>
+    </eStructuralFeatures>
+  </eClassifiers>
+  <eClassifiers xsi:type="ecore:EDataType" name="XMLName" instanceClassName="java.lang.String">
+    <eAnnotations source="http:///org/eclipse/emf/ecore/util/ExtendedMetaData">
+      <details key="pattern" value="\c*"/>
+    </eAnnotations>
+  </eClassifiers>
+  <eClassifiers xsi:type="ecore:EDataType" name="XMLNamespace" instanceClassName="java.lang.String">
+    <eAnnotations source="http:///org/eclipse/emf/ecore/util/ExtendedMetaData">
+      <details key="baseType" value="http://www.eclipse.org/emf/2003/XMLType#anyURI"/>
+    </eAnnotations>
+  </eClassifiers>
+  <eClassifiers xsi:type="ecore:EDataType" name="Wildcard" instanceClassName="java.lang.String">
+    <eAnnotations source="http:///org/eclipse/emf/ecore/util/ExtendedMetaData">
+      <details key="minLength" value="1"/>
+    </eAnnotations>
+  </eClassifiers>
+  <eClassifiers xsi:type="ecore:EDataType" name="Pattern" instanceClassName="java.lang.String">
+    <eAnnotations source="http:///org/eclipse/emf/ecore/util/ExtendedMetaData">
+      <details key="minLength" value="1"/>
+    </eAnnotations>
+  </eClassifiers>
+  <eClassifiers xsi:type="ecore:EEnum" name="FeatureKind">
+    <eLiterals name="unspecified"/>
+    <eLiterals name="simple" value="1"/>
+    <eLiterals name="attribute" value="2"/>
+    <eLiterals name="attributeWildcard" value="3"/>
+    <eLiterals name="element" value="4"/>
+    <eLiterals name="elementWildcard" value="5"/>
+    <eLiterals name="group" value="6"/>
+  </eClassifiers>
+  <eClassifiers xsi:type="ecore:EEnum" name="ContentKind">
+    <eLiterals name="unspecified"/>
+    <eLiterals name="empty" value="1"/>
+    <eLiterals name="simple" value="2"/>
+    <eLiterals name="mixed" value="3"/>
+    <eLiterals name="elementOnly" value="4"/>
+  </eClassifiers>
+  <eClassifiers xsi:type="ecore:EEnum" name="ProcessingKind">
+    <eLiterals name="unspecified"/>
+    <eLiterals name="strict" value="1"/>
+    <eLiterals name="lax" value="2"/>
+    <eLiterals name="skip" value="3"/>
+  </eClassifiers>
+  <eClassifiers xsi:type="ecore:EEnum" name="WhiteSpaceKind">
+    <eLiterals name="unspecified"/>
+    <eLiterals name="preserve" value="1"/>
+    <eLiterals name="replace" value="2"/>
+    <eLiterals name="collapse" value="3"/>
+  </eClassifiers>
+</ecore:EPackage>
diff --git a/plugins/org.eclipse.emf.ecore/plugin.properties b/plugins/org.eclipse.emf.ecore/plugin.properties
index 3804e58..a6db5dc 100644
--- a/plugins/org.eclipse.emf.ecore/plugin.properties
+++ b/plugins/org.eclipse.emf.ecore/plugin.properties
@@ -136,6 +136,7 @@
 _UI_InvocationDelegateRegistry_extensionpoint = Operation Invocation Delegate Factory Registry
 _UI_QueryDelegateRegistry_extensionpoint = Query Delegate Factory Registry
 _UI_ConversionDelegateRegistry_extensionpoint = Conversion Delegate Factory Registry
+_UI_AnnotationValidatorRegistry_extensionpoint = Annotation Validator Registry
 
 _UI_GenericInvariant_diagnostic = The ''{0}'' invariant is violated on ''{1}''
 _UI_GenericConstraint_diagnostic = The ''{0}'' constraint is violated on ''{1}''
@@ -225,3 +226,52 @@
 
 # This is in org.eclipse.emf.ecore.xmi
 #_UI_Ecore_content_type = Ecore File
+
+_UI_NameNotWellFormedJavaIdentifier_diagnostic = The name ''{0}'' is not a well-formed Java identifier
+
+_UI_BadXMLPattern_diagnostic = The value ''{0}'' is not a well-formed XML Schema pattern: {1}
+
+_UI_InvalidAnnotationLocation_diagnostic = This {0} annotation is only meaningful when it is directly contained by {1}
+_UI_InvalidDuplicateAnnotation_diagnostic = This {0} annotation is only meaningful when it is the first {0} annotation
+_UI_InvalidAnnotationEntryKey_diagnostic = This {0} annotation detail will be ignored because the key ''{1}'' is not recognized
+
+_UI_InvalidAnnotationEntryValue_diagnostic = This {0} annotation detail with key ''{1}'' contains a bad value
+
+_UI_InvalidValue_diagnostic = The value ''{0}'' is invalid: {1}
+
+_UI_InvalidReferenceValue_substitution = it cannot be converted to a ''{0}''
+
+_UI_MissingAnnotationEntryKey_diagnostic = A detail with key ''{0}'' is required
+
+_UI_IgnoredAnnotationReferences_diagnostic = This {0} annotation will ignore its references
+_UI_IgnoredAnnotationContents_diagnostic = This {0} annotation will ignore its contents
+_UI_IgnoredAnnotationAnnotations_diagnostic = This {0} annotation will ignore its nested annotations
+
+_UI_InvalidAnnotationReference_diagnostic The reference ''{1}'' is invalid for this {0} annotation
+_UI_InvalidAnnotationContent_diagnostic The nested content ''{1}'' is invalid for this {0} annotation
+_UI_InvalidAnnotationAnnotation_diagnostic The nested annotation ''{1}'' is invalid for this {0} annotation
+
+_UI_InvalidValueRequiredFeatureMustBeSet_diagnostic = The required feature must be set
+_UI_InvalidValueFeatureHasTooFewValues_diagnostic = The feature with {0} values must have at least {1} values
+_UI_InvalidValueFeatureHasTooManyValues_diagnostic = The feature with {0} values may have at most {1} values
+
+_UI_ValidEcoreAnnotationLocation_substitution = an Ecore package, classifier, or operation
+_UI_ValidExtendedMetaDataAnnotationLocation_substitution = an Ecore package, classifier, or structural feature
+
+_UI_ExtendeMetaDataAnnotationDetailNotBigDecimal_diagnostic = This ExtendedMetaData annotation detail with key ''{0}'' will be ignored because the data type isn''t a BigDecimal
+_UI_ExtendeMetaDataAnnotationDetailNotHasLength_diagnostic = This ExtendedMetaData annotation detail with key ''{0}'' will be ignored because the data type isn''t a String, Collection, or array
+_UI_ExtendeMetaDataAnnotationDetailNotRestrictEnum_diagnostic = This ExtendedMetaData annotation detail with key ''{0}'' will be ignored because an enum can''t be restricted
+_UI_ExtendeMetaDataAnnotationDetailNotList_diagnostic = This ExtendedMetaData annotation detail with key ''{0}'' will be ignored because the data type isn''t a List
+_UI_ExtendeMetaDataAnnotationDetailNotComparable_diagnostic = This ExtendedMetaData annotation detail with key ''{0}'' will be ignored because the data type isn''t a Comparable
+_UI_ExtendeMetaDataAnnotationDetailNotGlobalElement_diagnostic = This ExtendedMetaData annotation detail with key ''{0}'' will be ignored because the feature isn''t an element in a document root
+_UI_ExtendeMetaDataAnnotationDetailNotWildcard_diagnostic = This ExtendedMetaData annotation detail with key ''{0}'' will be ignored because the feature isn''t an element wildcard or attribute wildcard
+_UI_ExtendeMetaDataAnnotationDetailNotElementAttributeOrGroup_diagnostic = This ExtendedMetaData annotation detail with key ''{0}'' will be ignored because the feature isn''t an element, attribute, or group
+
+_UI_ExtendeMetaDataAnnotationDetailNotTypeResolved_diagnostic = The type reference ''{0}'' does not resolve to an Ecore data type
+_UI_ExtendeMetaDataAnnotationDetailNotTypeResolvedCorrectly_diagnostic = The type reference ''{0}'' resolves to an Ecore class not an Ecore data type
+_UI_ExtendeMetaDataAnnotationDetailNotTypeResolvedCorrectly_diagnostic = The type reference ''{0}'' resolves to an Ecore class not an Ecore data type
+_UI_ExtendeMetaDataAnnotationDetailTypeCircular_diagnostic = The type reference ''{0}'' leads to circular inheritance
+_UI_ExtendeMetaDataAnnotationDetailNotGroupResolved_diagnostic = The group reference ''{0}'' does not resolve to an Ecore structural feature
+_UI_ExtendeMetaDataAnnotationDetailNotAffiliationResolved_diagnostic = The affiliation reference ''{0}'' does not resolve to an Ecore structural feature
+_UI_ExtendeMetaDataAnnotationDetailGroupCircular_diagnostic = The group reference ''{0}'' leads to a circular group
+_UI_ExtendeMetaDataAnnotationDetailAffiliationCircular_diagnostic = The affiliation reference ''{0}'' leads to a circular affiliation
diff --git a/plugins/org.eclipse.emf.ecore/plugin.xml b/plugins/org.eclipse.emf.ecore/plugin.xml
index 8b4e416..b716bd2 100644
--- a/plugins/org.eclipse.emf.ecore/plugin.xml
+++ b/plugins/org.eclipse.emf.ecore/plugin.xml
@@ -15,6 +15,7 @@
    <extension-point id="invocation_delegate" name="%_UI_InvocationDelegateRegistry_extensionpoint" schema="schema/invocation_delegate.exsd"/>
    <extension-point id="query_delegate" name="%_UI_QueryDelegateRegistry_extensionpoint" schema="schema/query_delegate.exsd"/>
    <extension-point id="conversion_delegate" name="%_UI_ConversionDelegateRegistry_extensionpoint" schema="schema/conversion_delegate.exsd"/>
+   <extension-point id="annotation_validator" name="%_UI_AnnotationValidatorRegistry_extensionpoint" schema="schema/annotation_validator.exsd"/>
 
    <extension point="org.eclipse.emf.ecore.generated_package">
       <package
@@ -74,4 +75,17 @@
             priority="2000">
       </contentHandler>
    </extension>
+
+   <extension
+         point="org.eclipse.emf.ecore.annotation_validator">
+      <validator
+            uri="http://www.eclipse.org/emf/2002/Ecore"
+            class="org.eclipse.emf.ecore.util.EcoreAnnotationValidator">
+      </validator>
+      <validator
+            uri="http:///org/eclipse/emf/ecore/util/ExtendedMetaData"
+            class="org.eclipse.emf.ecore.util.ExtendedMetaDataAnnotationValidator">
+      </validator>
+   </extension>
+
 </plugin>
diff --git a/plugins/org.eclipse.emf.ecore/schema/annotation_validator.exsd b/plugins/org.eclipse.emf.ecore/schema/annotation_validator.exsd
new file mode 100644
index 0000000..47c669f
--- /dev/null
+++ b/plugins/org.eclipse.emf.ecore/schema/annotation_validator.exsd
@@ -0,0 +1,124 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<!-- Schema file written by PDE -->
+<schema targetNamespace="org.eclipse.emf.ecore" xmlns="http://www.w3.org/2001/XMLSchema">
+<annotation>
+      <appInfo>
+         <meta.schema plugin="org.eclipse.emf.ecore" id="annotation_validator" name="Annotation Validator"/>
+      </appInfo>
+      <documentation>
+         This extension point is used to define an annotation validator for validating annotations with the specified annotation source. The global EMF annotation validator registry, &lt;samp&gt;EAnnotationValidator.Registry.INSTANCE&lt;/samp&gt;, is used to record the registration.
+      </documentation>
+   </annotation>
+
+   <element name="extension">
+      <annotation>
+         <appInfo>
+            <meta.element />
+         </appInfo>
+      </annotation>
+      <complexType>
+         <sequence>
+            <element ref="validator" minOccurs="1" maxOccurs="unbounded"/>
+         </sequence>
+         <attribute name="point" type="string" use="required">
+            <annotation>
+               <documentation>
+                  A fully qualified identifier of the target extension point.
+               </documentation>
+            </annotation>
+         </attribute>
+         <attribute name="id" type="string">
+            <annotation>
+               <documentation>
+                  An optional identifier of the extension instance.
+               </documentation>
+            </annotation>
+         </attribute>
+         <attribute name="name" type="string">
+            <annotation>
+               <documentation>
+                  An optional name of the extension instance.
+               </documentation>
+            </annotation>
+         </attribute>
+      </complexType>
+   </element>
+
+   <element name="validator">
+      <annotation>
+         <appInfo>
+            <meta.element labelAttribute="id"/>
+         </appInfo>
+      </annotation>
+      <complexType>
+         <attribute name="uri" type="string" use="required">
+            <annotation>
+               <documentation>
+                  A URI identifying the annotation source of the annotation to be validated.
+               </documentation>
+            </annotation>
+         </attribute>
+         <attribute name="class" type="string" use="required">
+            <annotation>
+               <documentation>
+                  The fully qualified name of a Java class implementing &lt;samp&gt;org.eclipse.emf.ecore.EAnnotationValidator&lt;/samp&gt;.
+               </documentation>
+               <appInfo>
+                  <meta.attribute kind="java" basedOn=":org.eclipse.emf.ecore.EAnnotationValidator"/>
+               </appInfo>
+            </annotation>
+         </attribute>
+      </complexType>
+   </element>
+
+   <annotation>
+      <appInfo>
+         <meta.section type="since"/>
+      </appInfo>
+      <documentation>
+         2.14.0
+      </documentation>
+   </annotation>
+
+   <annotation>
+      <appInfo>
+         <meta.section type="examples"/>
+      </appInfo>
+      <documentation>
+         Following is an example of how a annotation validator can be registered: 
+&lt;pre&gt;
+  &lt;extension point=&quot;org.eclipse.emf.ecore.annotation_validator&quot; &gt;
+    &lt;validator uri=&quot;http://www.eclipse.org/emf/2002/Ecore&quot; class=&quot;org.eclipse.emf.ecore.util.EcoreAnnotationValidator&quot;/&gt; 
+  &lt;/extension&gt;
+&lt;/pre&gt;
+      </documentation>
+   </annotation>
+
+   <annotation>
+      <appInfo>
+         <meta.section type="apiInfo"/>
+      </appInfo>
+      <documentation>
+         The value of the class attribute must represent a class that implements &lt;samp&gt;org.eclipse.emf.ecore.EAnnotationValidator&lt;/samp&gt; and has a no argument contructor.
+&lt;p&gt;
+An annotation validator can be also registered from the source code with the &lt;samp&gt;EAnnotationValidator.Registry.INSTANCE&lt;/samp&gt; as follows:
+&lt;/p&gt;
+&lt;pre&gt;
+  EAnnotationValidator.Registry.INSTANCE.put(&quot;http://www.eclipse.org/emf/2002/Ecore&quot;, new EcoreAnnotationValidator());
+&lt;/pre&gt;
+      </documentation>
+   </annotation>
+
+
+   <annotation>
+      <appInfo>
+         <meta.section type="copyright"/>
+      </appInfo>
+      <documentation>
+         Copyright (c) 2017 Eclipse contributors and others.&lt;br&gt;
+All rights reserved. This program and the accompanying materials are made available under the terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at &lt;a 
+href=&quot;http://www.eclipse.org/legal/epl-v10.html&quot;&gt;http://www.eclipse.org/legal/epl-v10.html&lt;/a&gt;
+      </documentation>
+   </annotation>
+
+</schema>
diff --git a/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/EAnnotation.java b/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/EAnnotation.java
index 2fcfeca..9e229f8 100644
--- a/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/EAnnotation.java
+++ b/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/EAnnotation.java
@@ -30,7 +30,7 @@
  * </ul>
  *
  * @see org.eclipse.emf.ecore.EcorePackage#getEAnnotation()
- * @model annotation="http://www.eclipse.org/emf/2002/Ecore constraints='WellFormedSourceURI'"
+ * @model annotation="http://www.eclipse.org/emf/2002/Ecore constraints='WellFormed WellFormedSourceURI'"
  * @generated
  */
 public interface EAnnotation extends EModelElement
diff --git a/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/EAnnotationValidator.java b/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/EAnnotationValidator.java
new file mode 100644
index 0000000..dc90342
--- /dev/null
+++ b/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/EAnnotationValidator.java
@@ -0,0 +1,106 @@
+/**
+ * Copyright (c) 2017 Eclipse contributors and others.
+ * All rights reserved.   This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.eclipse.emf.ecore;
+
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.emf.common.util.DiagnosticChain;
+import org.eclipse.emf.ecore.util.BasicEAnnotationValidator;
+import org.eclipse.emf.ecore.util.EObjectValidator;
+
+
+/**
+ * An annotation validity checker for a specific {@link EAnnotation#getSource() annotation source}.
+ * <p>
+ * Implementations of EAnnotationValidator should extend {@link org.eclipse.emf.ecore.util.BasicEAnnotationValidator BasicEAnnotationValidator}
+ * or one of its derived classes
+ * because methods may be added to this API.
+ * </p>
+ *
+ * @since 2.14
+ * @see BasicEAnnotationValidator
+ *
+ * @noimplement Do not implement this interface directly; instead extend {@link BasicEAnnotationValidator} or one of its subclasses.
+ */
+public interface EAnnotationValidator
+{
+  /**
+   * An <code>EAnnotationValidator</code> wrapper used by the {@link EAnnotationValidator.Registry}.
+   */
+  interface Descriptor
+  {
+    /**
+     * Returns the annotation validator.
+     * @return the annotation validator.
+     */
+    EAnnotationValidator getEAnnotationValidator();
+  }
+
+  /**
+   * A map from {@link EAnnotation#getSource() annotation source} to {@link EAnnotationValidator} or to {@link Descriptor}.
+   */
+  interface Registry extends Map<String, Object>
+  {
+    /**
+     * Looks up the annotation source in the map.
+     */
+    EAnnotationValidator getEAnnotationValidator(String annotationSource);
+
+    /**
+     * The global instance of an annotation validator registry.
+     */
+    Registry INSTANCE = new Impl();
+
+    class Impl extends HashMap<String, Object> implements Registry
+    {
+      private static final long serialVersionUID = 1L;
+
+      @Override
+      public Object get(Object key)
+      {
+        Object eAnnotationValidator = super.get(key);
+        if (eAnnotationValidator instanceof EAnnotationValidator.Descriptor)
+        {
+          EAnnotationValidator.Descriptor eAnnotationValidatorDescriptor = (EAnnotationValidator.Descriptor)eAnnotationValidator;
+          eAnnotationValidator = eAnnotationValidatorDescriptor.getEAnnotationValidator();
+          put((String)key, eAnnotationValidator);
+          return eAnnotationValidator;
+        }
+        else
+        {
+          return eAnnotationValidator;
+        }
+      }
+
+      public EAnnotationValidator getEAnnotationValidator(String annotationSource)
+      {
+        return (EAnnotationValidator)get(annotationSource);
+      }
+    }
+  }
+
+  /**
+   * Returns whether this annotation with this annotation validator's {@link EAnnotation#getSource() annotation source} is valid at its {@link EAnnotation#getEModelElement() current location}.
+   * @param eAnnotation the annotation in question.
+   * @return whether this annotation with this annotation validator's annotation source is valid at its current location.
+   */
+  boolean isValidLocation(EAnnotation eAnnotation);
+
+  /**
+   * Returns whether this annotation is valid.
+   * @param eAnnotation the annotation in question.
+   * @param diagnostics a place to accumulate diagnostics; if it's <code>null</code>, no diagnostics should be produced.
+   * @param context a place to cache information, if it's <code>null</code>, no cache is supported.
+   * @return whether this annotation is valid.
+   *
+   * @see EObjectValidator#validate(EObject, DiagnosticChain, Map)
+   */
+  boolean validate(EAnnotation eAnnotation, DiagnosticChain diagnostics, Map<Object, Object> context);
+}
diff --git a/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/impl/EAnnotationImpl.java b/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/impl/EAnnotationImpl.java
index 55bafa0..fc7b480 100644
--- a/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/impl/EAnnotationImpl.java
+++ b/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/impl/EAnnotationImpl.java
@@ -452,7 +452,7 @@
   {
     if (eIsProxy()) return super.toString();
 
-    StringBuffer result = new StringBuffer(super.toString());
+    StringBuilder result = new StringBuilder(super.toString());
     result.append(" (source: ");
     result.append(source);
     result.append(')');
diff --git a/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/impl/EAttributeImpl.java b/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/impl/EAttributeImpl.java
index c85f571..39bd5e1 100644
--- a/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/impl/EAttributeImpl.java
+++ b/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/impl/EAttributeImpl.java
@@ -450,7 +450,7 @@
   {
     if (eIsProxy()) return super.toString();
 
-    StringBuffer result = new StringBuffer(super.toString());
+    StringBuilder result = new StringBuilder(super.toString());
     result.append(" (iD: ");
     result.append((eFlags & ID_EFLAG) != 0);
     result.append(')');
diff --git a/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/impl/EClassImpl.java b/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/impl/EClassImpl.java
index d323706..38bb154 100644
--- a/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/impl/EClassImpl.java
+++ b/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/impl/EClassImpl.java
@@ -1698,7 +1698,7 @@
   {
     if (eIsProxy()) return super.toString();
 
-    StringBuffer result = new StringBuffer(super.toString());
+    StringBuilder result = new StringBuilder(super.toString());
     result.append(" (abstract: ");
     result.append((eFlags & ABSTRACT_EFLAG) != 0);
     result.append(", interface: ");
diff --git a/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/impl/EDataTypeImpl.java b/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/impl/EDataTypeImpl.java
index d8b2ed9..774a853 100644
--- a/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/impl/EDataTypeImpl.java
+++ b/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/impl/EDataTypeImpl.java
@@ -327,7 +327,7 @@
   {
     if (eIsProxy()) return super.toString();
 
-    StringBuffer result = new StringBuffer(super.toString());
+    StringBuilder result = new StringBuilder(super.toString());
     result.append(" (serializable: ");
     result.append((eFlags & SERIALIZABLE_EFLAG) != 0);
     result.append(')');
diff --git a/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/impl/EEnumLiteralImpl.java b/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/impl/EEnumLiteralImpl.java
index 8fd534d..07ae049 100644
--- a/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/impl/EEnumLiteralImpl.java
+++ b/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/impl/EEnumLiteralImpl.java
@@ -431,7 +431,7 @@
   {
     if (eIsProxy()) return super.toString();
 
-    StringBuffer result = new StringBuffer(super.toString());
+    StringBuilder result = new StringBuilder(super.toString());
     result.append(" (value: ");
     result.append(value);
     result.append(", instance: ");
diff --git a/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/impl/ENamedElementImpl.java b/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/impl/ENamedElementImpl.java
index a3bc2a9..7d967ae 100644
--- a/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/impl/ENamedElementImpl.java
+++ b/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/impl/ENamedElementImpl.java
@@ -109,7 +109,7 @@
   {
     if (eIsProxy()) return super.toString();
 
-    StringBuffer result = new StringBuffer(super.toString());
+    StringBuilder result = new StringBuilder(super.toString());
     result.append(" (name: ");
     result.append(name);
     result.append(')');
diff --git a/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/impl/EPackageImpl.java b/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/impl/EPackageImpl.java
index 79d20f6..61e00f7 100644
--- a/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/impl/EPackageImpl.java
+++ b/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/impl/EPackageImpl.java
@@ -726,7 +726,7 @@
   {
     if (eIsProxy()) return super.toString();
 
-    StringBuffer result = new StringBuffer(super.toString());
+    StringBuilder result = new StringBuilder(super.toString());
     result.append(" (nsURI: ");
     result.append(nsURI);
     result.append(", nsPrefix: ");
diff --git a/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/impl/EReferenceImpl.java b/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/impl/EReferenceImpl.java
index 0969dca..152031f 100644
--- a/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/impl/EReferenceImpl.java
+++ b/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/impl/EReferenceImpl.java
@@ -600,7 +600,7 @@
   {
     if (eIsProxy()) return super.toString();
 
-    StringBuffer result = new StringBuffer(super.toString());
+    StringBuilder result = new StringBuilder(super.toString());
     result.append(" (containment: ");
     result.append((eFlags & CONTAINMENT_EFLAG) != 0);
     result.append(", resolveProxies: ");
diff --git a/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/impl/EStringToStringMapEntryImpl.java b/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/impl/EStringToStringMapEntryImpl.java
index 56705fb..67bdc4d 100644
--- a/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/impl/EStringToStringMapEntryImpl.java
+++ b/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/impl/EStringToStringMapEntryImpl.java
@@ -233,7 +233,7 @@
   {
     if (eIsProxy()) return super.toString();
 
-    StringBuffer result = new StringBuffer(super.toString());
+    StringBuilder result = new StringBuilder(super.toString());
     result.append(" (key: ");
     result.append(key);
     result.append(", value: ");
diff --git a/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/impl/EStructuralFeatureImpl.java b/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/impl/EStructuralFeatureImpl.java
index 43b3bbf..fd9c4d2 100644
--- a/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/impl/EStructuralFeatureImpl.java
+++ b/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/impl/EStructuralFeatureImpl.java
@@ -467,7 +467,7 @@
   {
     if (eIsProxy()) return super.toString();
 
-    StringBuffer result = new StringBuffer(super.toString());
+    StringBuilder result = new StringBuilder(super.toString());
     result.append(" (changeable: ");
     result.append((eFlags & CHANGEABLE_EFLAG) != 0);
     result.append(", volatile: ");
diff --git a/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/impl/ETypedElementImpl.java b/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/impl/ETypedElementImpl.java
index 0490392..00e2b6b 100644
--- a/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/impl/ETypedElementImpl.java
+++ b/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/impl/ETypedElementImpl.java
@@ -678,7 +678,7 @@
   {
     if (eIsProxy()) return super.toString();
 
-    StringBuffer result = new StringBuffer(super.toString());
+    StringBuilder result = new StringBuilder(super.toString());
     result.append(" (ordered: ");
     result.append((eFlags & ORDERED_EFLAG) != 0);
     result.append(", unique: ");
diff --git a/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/impl/EcorePackageImpl.java b/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/impl/EcorePackageImpl.java
index 8803562..f7b5a29 100644
--- a/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/impl/EcorePackageImpl.java
+++ b/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/impl/EcorePackageImpl.java
@@ -459,7 +459,7 @@
 
   /**
    * Creates, registers, and initializes the <b>Package</b> for this model, and for any others upon which it depends.
-   * 
+   *
    * <p>This method is used to initialize {@link EcorePackage#eINSTANCE} when that field is accessed.
    * Clients should not invoke it directly. Instead, they should simply access that field to obtain the package.
    * <!-- begin-user-doc -->
@@ -474,7 +474,8 @@
     if (isInited) return (EcorePackage)EPackage.Registry.INSTANCE.getEPackage(EcorePackage.eNS_URI);
 
     // Obtain or create and register package
-    EcorePackageImpl theEcorePackage = (EcorePackageImpl)(EPackage.Registry.INSTANCE.get(eNS_URI) instanceof EcorePackageImpl ? EPackage.Registry.INSTANCE.get(eNS_URI) : new EcorePackageImpl());
+    Object registeredEcorePackage = EPackage.Registry.INSTANCE.get(eNS_URI);
+    EcorePackageImpl theEcorePackage = registeredEcorePackage instanceof EcorePackageImpl ? (EcorePackageImpl)registeredEcorePackage : new EcorePackageImpl();
 
     isInited = true;
 
@@ -486,7 +487,7 @@
 
     // Register package validator
     EValidator.Registry.INSTANCE.put
-      (theEcorePackage, 
+      (theEcorePackage,
        new EValidator.Descriptor()
        {
          public EValidator getEValidator()
@@ -495,7 +496,6 @@
          }
        });
 
-  
     // Update the registry and return the package
     EPackage.Registry.INSTANCE.put(EcorePackage.eNS_URI, theEcorePackage);
     return theEcorePackage;
@@ -2846,90 +2846,90 @@
    */
   protected void createEcoreAnnotations()
   {
-    String source = "http://www.eclipse.org/emf/2002/Ecore";	
+    String source = "http://www.eclipse.org/emf/2002/Ecore";
     addAnnotation
-      (eAttributeEClass, 
-       source, 
-       new String[] 
+      (eAttributeEClass,
+       source,
+       new String[]
        {
-       "constraints", "ConsistentTransient"
-       });	
+         "constraints", "ConsistentTransient"
+       });
     addAnnotation
-      (eAnnotationEClass, 
-       source, 
-       new String[] 
+      (eAnnotationEClass,
+       source,
+       new String[]
        {
-       "constraints", "WellFormedSourceURI"
-       });	
+         "constraints", "WellFormed WellFormedSourceURI"
+       });
     addAnnotation
-      (eClassEClass, 
-       source, 
-       new String[] 
+      (eClassEClass,
+       source,
+       new String[]
        {
-       "constraints", "InterfaceIsAbstract AtMostOneID UniqueFeatureNames UniqueOperationSignatures NoCircularSuperTypes WellFormedMapEntryClass ConsistentSuperTypes DisjointFeatureAndOperationSignatures"
-       });	
+         "constraints", "InterfaceIsAbstract AtMostOneID UniqueFeatureNames UniqueOperationSignatures NoCircularSuperTypes WellFormedMapEntryClass ConsistentSuperTypes DisjointFeatureAndOperationSignatures"
+       });
     addAnnotation
-      (eClassifierEClass, 
-       source, 
-       new String[] 
+      (eClassifierEClass,
+       source,
+       new String[]
        {
-       "constraints", "WellFormedInstanceTypeName UniqueTypeParameterNames"
-       });	
+         "constraints", "WellFormedInstanceTypeName UniqueTypeParameterNames"
+       });
     addAnnotation
-      (eEnumEClass, 
-       source, 
-       new String[] 
+      (eEnumEClass,
+       source,
+       new String[]
        {
-       "constraints", "UniqueEnumeratorNames UniqueEnumeratorLiterals"
-       });	
+         "constraints", "UniqueEnumeratorNames UniqueEnumeratorLiterals"
+       });
     addAnnotation
-      (eNamedElementEClass, 
-       source, 
-       new String[] 
+      (eNamedElementEClass,
+       source,
+       new String[]
        {
-       "constraints", "WellFormedName"
-       });	
+         "constraints", "WellFormedName"
+       });
     addAnnotation
-      (eOperationEClass, 
-       source, 
-       new String[] 
+      (eOperationEClass,
+       source,
+       new String[]
        {
-       "constraints", "UniqueParameterNames UniqueTypeParameterNames NoRepeatingVoid"
-       });	
+         "constraints", "UniqueParameterNames UniqueTypeParameterNames NoRepeatingVoid"
+       });
     addAnnotation
-      (ePackageEClass, 
-       source, 
-       new String[] 
+      (ePackageEClass,
+       source,
+       new String[]
        {
-       "constraints", "WellFormedNsURI WellFormedNsPrefix UniqueSubpackageNames UniqueClassifierNames UniqueNsURIs"
-       });	
+         "constraints", "WellFormedNsURI WellFormedNsPrefix UniqueSubpackageNames UniqueClassifierNames UniqueNsURIs"
+       });
     addAnnotation
-      (eReferenceEClass, 
-       source, 
-       new String[] 
+      (eReferenceEClass,
+       source,
+       new String[]
        {
-       "constraints", "ConsistentOpposite SingleContainer ConsistentKeys ConsistentUnique ConsistentContainer"
-       });	
+         "constraints", "ConsistentOpposite SingleContainer ConsistentKeys ConsistentUnique ConsistentContainer"
+       });
     addAnnotation
-      (eStructuralFeatureEClass, 
-       source, 
-       new String[] 
+      (eStructuralFeatureEClass,
+       source,
+       new String[]
        {
-       "constraints", "ValidDefaultValueLiteral"
-       });	
+         "constraints", "ValidDefaultValueLiteral"
+       });
     addAnnotation
-      (eTypedElementEClass, 
-       source, 
-       new String[] 
+      (eTypedElementEClass,
+       source,
+       new String[]
        {
-       "constraints", "ValidLowerBound ValidUpperBound ConsistentBounds ValidType"
-       });	
+         "constraints", "ValidLowerBound ValidUpperBound ConsistentBounds ValidType"
+       });
     addAnnotation
-      (eGenericTypeEClass, 
-       source, 
-       new String[] 
+      (eGenericTypeEClass,
+       source,
+       new String[]
        {
-       "constraints", "ConsistentType ConsistentBounds ConsistentArguments"
+         "constraints", "ConsistentType ConsistentBounds ConsistentArguments"
        });
   }
 
@@ -2941,147 +2941,147 @@
    */
   protected void createExtendedMetaDataAnnotations()
   {
-    String source = "http:///org/eclipse/emf/ecore/util/ExtendedMetaData";	
+    String source = "http:///org/eclipse/emf/ecore/util/ExtendedMetaData";
     addAnnotation
-      (eBigDecimalEDataType, 
-       source, 
-       new String[] 
+      (eBigDecimalEDataType,
+       source,
+       new String[]
        {
-       "baseType", "http://www.w3.org/2001/XMLSchema#decimal"
-       });	
+         "baseType", "http://www.w3.org/2001/XMLSchema#decimal"
+       });
     addAnnotation
-      (eBigIntegerEDataType, 
-       source, 
-       new String[] 
+      (eBigIntegerEDataType,
+       source,
+       new String[]
        {
-       "baseType", "http://www.w3.org/2001/XMLSchema#integer"
-       });	
+         "baseType", "http://www.w3.org/2001/XMLSchema#integer"
+       });
     addAnnotation
-      (eBooleanEDataType, 
-       source, 
-       new String[] 
+      (eBooleanEDataType,
+       source,
+       new String[]
        {
-       "baseType", "http://www.w3.org/2001/XMLSchema#boolean"
-       });	
+         "baseType", "http://www.w3.org/2001/XMLSchema#boolean"
+       });
     addAnnotation
-      (eBooleanObjectEDataType, 
-       source, 
-       new String[] 
+      (eBooleanObjectEDataType,
+       source,
+       new String[]
        {
-       "baseType", "EBoolean",
-       "name", "EBoolean:Object"
-       });	
+         "baseType", "EBoolean",
+         "name", "EBoolean:Object"
+       });
     addAnnotation
-      (eByteEDataType, 
-       source, 
-       new String[] 
+      (eByteEDataType,
+       source,
+       new String[]
        {
-       "baseType", "http://www.w3.org/2001/XMLSchema#byte"
-       });	
+         "baseType", "http://www.w3.org/2001/XMLSchema#byte"
+       });
     addAnnotation
-      (eByteArrayEDataType, 
-       source, 
-       new String[] 
+      (eByteArrayEDataType,
+       source,
+       new String[]
        {
-       "baseType", "http://www.w3.org/2001/XMLSchema#hexBinary"
-       });	
+         "baseType", "http://www.w3.org/2001/XMLSchema#hexBinary"
+       });
     addAnnotation
-      (eByteObjectEDataType, 
-       source, 
-       new String[] 
+      (eByteObjectEDataType,
+       source,
+       new String[]
        {
-       "baseType", "EByte",
-       "name", "EByte:Object"
-       });	
+         "baseType", "EByte",
+         "name", "EByte:Object"
+       });
     addAnnotation
-      (eCharacterObjectEDataType, 
-       source, 
-       new String[] 
+      (eCharacterObjectEDataType,
+       source,
+       new String[]
        {
-       "baseType", "EChar",
-       "name", "EChar:Object"
-       });	
+         "baseType", "EChar",
+         "name", "EChar:Object"
+       });
     addAnnotation
-      (eDoubleEDataType, 
-       source, 
-       new String[] 
+      (eDoubleEDataType,
+       source,
+       new String[]
        {
-       "baseType", "http://www.w3.org/2001/XMLSchema#double"
-       });	
+         "baseType", "http://www.w3.org/2001/XMLSchema#double"
+       });
     addAnnotation
-      (eDoubleObjectEDataType, 
-       source, 
-       new String[] 
+      (eDoubleObjectEDataType,
+       source,
+       new String[]
        {
-       "baseType", "EDouble",
-       "name", "EDouble:Object"
-       });	
+         "baseType", "EDouble",
+         "name", "EDouble:Object"
+       });
     addAnnotation
-      (eFloatEDataType, 
-       source, 
-       new String[] 
+      (eFloatEDataType,
+       source,
+       new String[]
        {
-       "baseType", "http://www.w3.org/2001/XMLSchema#float"
-       });	
+         "baseType", "http://www.w3.org/2001/XMLSchema#float"
+       });
     addAnnotation
-      (eFloatObjectEDataType, 
-       source, 
-       new String[] 
+      (eFloatObjectEDataType,
+       source,
+       new String[]
        {
-       "baseType", "EFloat",
-       "name", "EFloat:Object"
-       });	
+         "baseType", "EFloat",
+         "name", "EFloat:Object"
+       });
     addAnnotation
-      (eIntEDataType, 
-       source, 
-       new String[] 
+      (eIntEDataType,
+       source,
+       new String[]
        {
-       "baseType", "http://www.w3.org/2001/XMLSchema#int"
-       });	
+         "baseType", "http://www.w3.org/2001/XMLSchema#int"
+       });
     addAnnotation
-      (eIntegerObjectEDataType, 
-       source, 
-       new String[] 
+      (eIntegerObjectEDataType,
+       source,
+       new String[]
        {
-       "baseType", "EInt",
-       "name", "EInt:Object"
-       });	
+         "baseType", "EInt",
+         "name", "EInt:Object"
+       });
     addAnnotation
-      (eLongEDataType, 
-       source, 
-       new String[] 
+      (eLongEDataType,
+       source,
+       new String[]
        {
-       "baseType", "http://www.w3.org/2001/XMLSchema#long"
-       });	
+         "baseType", "http://www.w3.org/2001/XMLSchema#long"
+       });
     addAnnotation
-      (eLongObjectEDataType, 
-       source, 
-       new String[] 
+      (eLongObjectEDataType,
+       source,
+       new String[]
        {
-       "baseType", "ELong",
-       "name", "ELong:Object"
-       });	
+         "baseType", "ELong",
+         "name", "ELong:Object"
+       });
     addAnnotation
-      (eShortEDataType, 
-       source, 
-       new String[] 
+      (eShortEDataType,
+       source,
+       new String[]
        {
-       "baseType", "http://www.w3.org/2001/XMLSchema#short"
-       });	
+         "baseType", "http://www.w3.org/2001/XMLSchema#short"
+       });
     addAnnotation
-      (eShortObjectEDataType, 
-       source, 
-       new String[] 
+      (eShortObjectEDataType,
+       source,
+       new String[]
        {
-       "baseType", "EShort",
-       "name", "EShort:Object"
-       });	
+         "baseType", "EShort",
+         "name", "EShort:Object"
+       });
     addAnnotation
-      (eStringEDataType, 
-       source, 
-       new String[] 
+      (eStringEDataType,
+       source,
+       new String[]
        {
-       "baseType", "http://www.w3.org/2001/XMLSchema#string"
+         "baseType", "http://www.w3.org/2001/XMLSchema#string"
        });
   }
 
diff --git a/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/plugin/AnnotationValidatorRegistryReader.java b/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/plugin/AnnotationValidatorRegistryReader.java
new file mode 100644
index 0000000..1a5696b
--- /dev/null
+++ b/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/plugin/AnnotationValidatorRegistryReader.java
@@ -0,0 +1,119 @@
+/**
+ * Copyright (c) 2017 Eclipse contributors and others.
+ * All rights reserved.   This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.eclipse.emf.ecore.plugin;
+
+
+import java.lang.reflect.Field;
+
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.RegistryFactory;
+import org.eclipse.emf.common.CommonPlugin;
+import org.eclipse.emf.common.util.WrappedException;
+import org.eclipse.emf.ecore.EAnnotationValidator;
+
+
+/**
+ * A plugin extension reader that populates the
+ * {@link org.eclipse.emf.ecore.EAnnotationValidator.Registry#INSTANCE global} annotation validator registry.
+ * Clients are not expected to use this class directly.
+ */
+class AnnotationValidatorRegistryReader extends RegistryReader
+{
+  static class AnnotationValidatorDescriptor extends PluginClassDescriptor implements EAnnotationValidator.Descriptor
+  {
+    protected EAnnotationValidator eAnnotationValidator;
+
+    public AnnotationValidatorDescriptor(IConfigurationElement e, String attrName)
+    {
+      super(e, attrName);
+    }
+
+    public EAnnotationValidator getEAnnotationValidator()
+    {
+      try
+      {
+        Class<?> javaClass = CommonPlugin.loadClass(element.getDeclaringExtension().getContributor().getName(), element.getAttribute(attributeName));
+        try
+        {
+          // First try to see if this class has an INSTANCE field
+          //
+          Field field = javaClass.getField("INSTANCE");
+          Object result = field.get(null);
+          return (EAnnotationValidator)result;
+        }
+        catch (NoSuchFieldError e)
+        {
+          // If not, create a new instance.
+          return (EAnnotationValidator)javaClass.newInstance();
+        }
+      }
+      catch (ClassNotFoundException e)
+      {
+        throw new WrappedException(e);
+      }
+      catch (IllegalAccessException e)
+      {
+        throw new WrappedException(e);
+      }
+      catch (NoSuchFieldException e)
+      {
+        throw new WrappedException(e);
+      }
+      catch (InstantiationException e)
+      {
+        throw new WrappedException(e);
+      }
+    }
+  }
+
+  static final String TAG_VALIDATOR = "validator";
+
+  static final String ATT_URI = "uri";
+
+  static final String ATT_CLASS = "class";
+
+  public AnnotationValidatorRegistryReader()
+  {
+    super(RegistryFactory.getRegistry(), EcorePlugin.INSTANCE.getSymbolicName(), EcorePlugin.ANNOTATION_VALIDATOR_PPID);
+  }
+
+  @Override
+  protected boolean readElement(IConfigurationElement element, boolean add)
+  {
+    if (element.getName().equals(TAG_VALIDATOR))
+    {
+      String uri = element.getAttribute(ATT_URI);
+      if (uri == null)
+      {
+        logMissingAttribute(element, ATT_URI);
+      }
+      else if (element.getAttribute(ATT_CLASS) == null)
+      {
+        logMissingAttribute(element, ATT_CLASS);
+      }
+      else if (add)
+      {
+        Object previous = EAnnotationValidator.Registry.INSTANCE.put(uri, new AnnotationValidatorDescriptor(element, ATT_CLASS));
+        if (previous instanceof AnnotationValidatorDescriptor)
+        {
+          AnnotationValidatorDescriptor descriptor = (AnnotationValidatorDescriptor)previous;
+          EcorePlugin.INSTANCE.log(
+            "Both '" + descriptor.element.getContributor().getName() + "' and '" + element.getContributor().getName() + "' register an annotation validator for '" + uri + "'");
+        }
+        return true;
+      }
+      else
+      {
+        EAnnotationValidator.Registry.INSTANCE.remove(uri);
+        return true;
+      }
+    }
+
+    return false;
+  }
+}
\ No newline at end of file
diff --git a/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/plugin/EcorePlugin.java b/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/plugin/EcorePlugin.java
index 1531e8a..b95fd53 100644
--- a/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/plugin/EcorePlugin.java
+++ b/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/plugin/EcorePlugin.java
@@ -927,6 +927,7 @@
       new InvocationDelegateFactoryRegistryReader().readRegistry();
       new QueryDelegateFactoryRegistryReader().readRegistry();
       new ConversionDelegateFactoryRegistryReader().readRegistry();
+      new AnnotationValidatorRegistryReader().readRegistry();
     }
   }
 
@@ -1431,4 +1432,9 @@
   public static final String INVOCATION_DELEGATE_PPID = "invocation_delegate";
   public static final String QUERY_DELEGATE_PPID = "query_delegate";
   public static final String CONVERSION_DELEGATE_PPID = "conversion_delegate";
+
+  /**
+   * Since 2.14
+   */
+  public static final String ANNOTATION_VALIDATOR_PPID = "annotation_validator";
 }
\ No newline at end of file
diff --git a/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/util/BasicEAnnotationValidator.java b/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/util/BasicEAnnotationValidator.java
new file mode 100644
index 0000000..7cd7423
--- /dev/null
+++ b/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/util/BasicEAnnotationValidator.java
@@ -0,0 +1,1920 @@
+/**
+ * Copyright (c) 2017 Eclipse contributors and others.
+ * All rights reserved.   This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.eclipse.emf.ecore.util;
+
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.emf.common.util.BasicDiagnostic;
+import org.eclipse.emf.common.util.Diagnostic;
+import org.eclipse.emf.common.util.DiagnosticChain;
+import org.eclipse.emf.common.util.EList;
+import org.eclipse.emf.common.util.ResourceLocator;
+import org.eclipse.emf.ecore.EAnnotation;
+import org.eclipse.emf.ecore.EAnnotationValidator;
+import org.eclipse.emf.ecore.EAttribute;
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EDataType;
+import org.eclipse.emf.ecore.EModelElement;
+import org.eclipse.emf.ecore.ENamedElement;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EReference;
+import org.eclipse.emf.ecore.EStructuralFeature;
+import org.eclipse.emf.ecore.ETypedElement;
+import org.eclipse.emf.ecore.EValidator;
+import org.eclipse.emf.ecore.EcoreFactory;
+import org.eclipse.emf.ecore.EcorePackage;
+import org.eclipse.emf.ecore.plugin.EcorePlugin;
+import org.eclipse.emf.ecore.xml.type.XMLTypeFactory;
+
+
+/**
+ * A basic implementation of an {@link EAnnotationValidator annotation validator}.
+ * <p>
+ * An implementation must specialize the {@link #getResourceLocator()} method in order for the {@link #getValidLocationDescription()} method to function correctly.
+ * The most straight-forward way to implement an annotation validator is to model the supported keys,
+ * specializing {@link #getPropertyClasses(EModelElement)} with one or more {@link EClass classes} that
+ * can be {@link #createInstance(EClass, EAnnotation) instantiated} to represent the information in the annotation.
+ * These classes are used to induce {@link #getProperties(EModelElement) a mapping} of keys onto the underlying annotation model's features.
+ * If the annotation model includes references,
+ * {@link #validateReferenceDetailValueLiteral(EAnnotation, EModelElement, Map.Entry, EReference, String, List, DiagnosticChain, Map) validateReferenceDetailValueLiteral}
+ * and {@link #convertPropertyReferenceValueToLiteralItem(EObject, EReference, Object)} must also be specialized.
+ * Alternatively an implementation can specialize {@link #validateDetail(EAnnotation, EModelElement, Map.Entry, DiagnosticChain, Map)} without providing a modeled representation.
+ * The annotation validator's {@link #getAssistant() assistant} is especially useful for inducing a user interface based on the modeled annotation representation.
+ * </p>
+ *
+ * @see EAnnotationValidator
+ * @see Assistant
+ * @since 2.14
+ */
+public abstract class BasicEAnnotationValidator implements EAnnotationValidator
+{
+  /**
+   * @see #reportInvalidLocation(EAnnotation, DiagnosticChain, Map)
+   */
+  public static final int INVALID_LOCATION = 1;
+
+  /**
+   * @see #reportDuplicate(EAnnotation, EAnnotation, EModelElement, DiagnosticChain, Map)
+   */
+  public static final int INVALID_DUPLICATE = 2;
+
+  /**
+   * @see #reportInvalidReferenceLiteral(EAnnotation, EModelElement, Map.Entry, EReference, String, DiagnosticChain, Map)
+   */
+  public static final int INVALID_REFERENCE_LITERAL = 3;
+
+  /**
+   * @see #createValueDiagnostic(EAnnotation, EModelElement, Map.Entry, EStructuralFeature)
+   */
+  public static final int INVALID_DETAIL_VALUE = 4;
+
+  /**
+   * @see #reportInvalidValueLiteral(EAnnotation, EModelElement, Map.Entry, EAttribute, String, EDataType, DiagnosticChain, RuntimeException, Map)
+   */
+  public static final int INVALID_VALUE_LITERAL = 5;
+
+  /**
+   * @see #reportIgnoredAnnotations(EAnnotation, EModelElement, Collection, DiagnosticChain, Map)
+   */
+  public static final int IGNORED_ANNOTATIONS = 6;
+
+  /**
+   * @see #reportIgnoredContents(EAnnotation, EModelElement, Collection, DiagnosticChain, Map)
+   */
+  public static final int IGNORED_CONTENTS = 7;
+
+  /**
+   * @see #reportIgnoredReferences(EAnnotation, EModelElement, Collection, DiagnosticChain, Map)
+   */
+  public static final int IGNORED_REFERENCES = 8;
+
+  /**
+   * @see #reportInvalidReference(EAnnotation, EModelElement, EObject, DiagnosticChain, Map)
+   */
+  public static final int INVALID_REFERENCE = 9;
+
+  /**
+   * @see #reportInvalidAnnotation(EAnnotation, EModelElement, EAnnotation, DiagnosticChain, Map)
+   */
+  public static final int INVALID_ANNOTATION = 10;
+
+  /**
+   * @see #reportInvalidContent(EAnnotation, EModelElement, EObject, DiagnosticChain, Map)
+   */
+  public static final int INVALID_CONTENT = 11;
+
+  /**
+   * @see #reportIgnoredEntry(EAnnotation, EModelElement, Map.Entry, DiagnosticChain, Map)
+   */
+  public static final int IGNORED_ENTRY = 12;
+
+  /**
+   * @see #reportMissingEntry(EAnnotation, EModelElement, String, EStructuralFeature, DiagnosticChain, Map)
+   */
+  public static final int MISSING_ENTRY = 13;
+
+  /**
+   * @see #reportMissingRequiredEntryValue(EAnnotation, EModelElement, EStructuralFeature, List, DiagnosticChain, Map)
+   */
+  public static final int MISSING_REQUIRED_ENTRY_VALUE = 14;
+
+  /**
+   * @see #reportTooFewValues(EAnnotation, EModelElement, Map.Entry, EStructuralFeature, List, int, int, DiagnosticChain, Map)
+   */
+  public static final int TOO_FEW_VALUES = 15;
+
+  /**
+   * @see #reportTooManyValues(EAnnotation, EModelElement, Map.Entry, EStructuralFeature, List, int, int, DiagnosticChain, Map)
+   */
+  public static final int TOO_MANY_VALUES = 16;
+
+  /**
+   * The {@link EAnnotation#getSource() annotation source} validated by this annotation validator.
+   */
+  protected final String annotationSource;
+
+  /**
+   * The name used in messages for this validator's annotations.
+   */
+  protected final String annotationName;
+
+  /**
+   * The {@link Diagnostic#getSource() source} used in this validator's diagnostics.
+   */
+  protected final String diagnosticSource;
+
+  /**
+   * The {@link Assistant assistant} used by the framework to induce a user interface.
+   */
+  protected final Assistant assistant;
+
+  /**
+   * Creates an instance for the given {@link EAnnotation#getSource() annotation source} validated by this annotation validator.
+   *
+   * @param annotationSource the annotation source validated by this annotation validator.
+   * @param annotationName the name used in this validator's diagnostics
+   * @param diagnosticSource the {@link Diagnostic#getSource() diagnostic source} used in this validator's diagnostics.
+   */
+  public BasicEAnnotationValidator(String annotationSource, String annotationName, String diagnosticSource)
+  {
+    this.annotationSource = annotationSource;
+    this.annotationName = annotationName;
+    this.diagnosticSource = diagnosticSource;
+    this.assistant = createAssistant();
+  }
+
+  /**
+   * Returns the resource locator for fetching implementation-specific messages.
+   * @return the resource locator for fetching model-specific messages.
+   */
+  protected abstract ResourceLocator getResourceLocator();
+
+  /**
+   * Returns the model classes used to represent annotations for the given model element.
+   * <p>
+   * Typically an annotation validator implementation will return a single class.
+   * An induced user interface will generally require the ability to {@link #createInstance(EClass, EAnnotation) create instances} of the classes returned by this method.
+   * The annotation validator implementation itself does not require that ability.
+   * </p>
+   * @param eModelElement the model element in question.
+   * @return the model classes used to represent annotations for the given model element.
+   */
+  protected abstract List<EClass> getPropertyClasses(EModelElement eModelElement);
+
+  /**
+   * Returns the assistant provided by this annotation validator
+   * which is generally useful to provide access to protected methods that are needed primarily for inducing a user interface that represents the annotations in a more structured form.
+   * @return the assistant provided by this annotation validator.
+   */
+  public Assistant getAssistant()
+  {
+    return assistant;
+  }
+
+  /**
+   * Creates the assistant.
+   * <p>
+   * Generally derived classes will not need to specialize this method because all methods of the assistant delegate back to the annotation validator.
+   * </p>
+   * @return the assistant.
+   */
+  protected Assistant createAssistant()
+  {
+    return new Assistant(this)
+      {
+      };
+  }
+
+  /**
+   * {@inheritDoc}
+   * <p>
+   * This implementation returns <code>false</code> if the containing {@link EAnnotation#getEModelElement()} is <code>null</code>,
+   * if the {@link #isValidLocation(EAnnotation, EModelElement)} returns <code>false</code> for the containing model element,
+   * or if this is not the first annotation with this annotation source in the model element and {@link #isDuplicateValid(EModelElement, EAnnotation, EAnnotation) isDuplicateValue} returns <code>false</code>.
+   * </p>
+   */
+  public boolean isValidLocation(EAnnotation eAnnotation)
+  {
+    EModelElement eModelElement = eAnnotation.getEModelElement();
+    if (eModelElement == null || !isValidLocation(eAnnotation, eModelElement))
+    {
+      return false;
+    }
+    else
+    {
+      EAnnotation otherEAnnotation = eModelElement.getEAnnotation(annotationSource);
+      return otherEAnnotation == null || otherEAnnotation == eAnnotation || isDuplicateValid(eModelElement, otherEAnnotation, eAnnotation);
+    }
+  }
+
+  /**
+   * Returns whether this annotation {@link EAnnotation#getEModelElement() contained} by this model element is valid at this location.
+   * <p>
+   * This implementation returns <code>false</code> if the element is not a {@link ENamedElement named element}.
+   * It's typically the case that annotations on annotations aren't meaningful and valid.
+   * </p>
+   * @param eAnnotation the annotation in question.
+   * @param eModelElement the annotation's {@link EAnnotation#getEModelElement() containing} model element.
+   * @return whether this annotation contained by this model element is valid at this location.
+   *
+   * @see #isValidLocation(EAnnotation)
+   * @see #validate(EAnnotation, DiagnosticChain, Map)
+   */
+  protected boolean isValidLocation(EAnnotation eAnnotation, EModelElement eModelElement)
+  {
+    return eModelElement instanceof ENamedElement;
+  }
+
+  /**
+   * Returns whether the given two annotations, both with the annotation validator's annotation source, both {@link EModelElement#getEAnnotation(String) contained} by the given model element, are valid.
+   * <p>
+   * This implementation returns <code>false</code> because it's typically the case that only the primary annotation is meaningful and valid.
+   * </p>
+   * @param eModelElement the model element that contains both annotations in its {@link EModelElement#getEAnnotations() annotations} feature.
+   * @param primaryEAnnotation the first annotation in the model element's details.
+   * @param secondaryEAnnotation a subsequent annotation in the model element's details.
+   * @return whether these two annotations, both of which have this annotation validator's annotation source, are valid.
+   * @see #isValidLocation(EAnnotation)
+   * @see #validate(EAnnotation, DiagnosticChain, Map)
+   */
+  protected boolean isDuplicateValid(EModelElement eModelElement, EAnnotation primaryEAnnotation, EAnnotation secondaryEAnnotation)
+  {
+    return false;
+  }
+
+  /**
+   * {@inheritDoc}
+   * <p>
+   * This implementation checks if the {@link #isValidLocation(EAnnotation, EModelElement) location is valid}
+   * and {@link #reportInvalidLocation(EAnnotation, DiagnosticChain, Map) reports an invalid location} if it is not.
+   * Then checks for {@link #isDuplicateValid(EModelElement, EAnnotation, EAnnotation) invalid duplicates}
+   * and {@link #reportDuplicate(EAnnotation, EAnnotation, EModelElement, DiagnosticChain, Map) reports a duplicate} if it is an invalid duplicate.
+   * Then it {@link #validateReferences(EAnnotation, EModelElement, DiagnosticChain, Map) validates the references} and {@link #validateDetails(EAnnotation, EModelElement, DiagnosticChain, Map) validates the details}.
+   * </p>
+   */
+  public boolean validate(EAnnotation eAnnotation, DiagnosticChain diagnostics, Map<Object, Object> context)
+  {
+    boolean result;
+    EModelElement eModelElement = eAnnotation.getEModelElement();
+    if (eModelElement != null && isValidLocation(eAnnotation, eModelElement))
+    {
+      EAnnotation otherEAnnotation = eModelElement.getEAnnotation(annotationSource);
+      if (otherEAnnotation == eAnnotation || isDuplicateValid(eModelElement, otherEAnnotation, eAnnotation))
+      {
+        result = validateReferences(eAnnotation, eModelElement, diagnostics, context);
+        if (result || diagnostics != null)
+        {
+          result &= validateContents(eAnnotation, eModelElement, diagnostics, context);
+        }
+        if (result || diagnostics != null)
+        {
+          result &= validateAnnotations(eAnnotation, eModelElement, diagnostics, context);
+        }
+        if (result || diagnostics != null)
+        {
+          result &= validateDetails(eAnnotation, eModelElement, diagnostics, context);
+        }
+      }
+      else
+      {
+        result = false;
+        if (diagnostics != null)
+        {
+          reportDuplicate(otherEAnnotation, eAnnotation, eModelElement, diagnostics, context);
+        }
+      }
+    }
+    else
+    {
+      result = false;
+      if (diagnostics != null)
+      {
+        reportInvalidLocation(eAnnotation, diagnostics, context);
+      }
+    }
+    return result;
+  }
+
+  /**
+   * Returns whether this annotation's {@link EAnnotation#getReferences() references} are valid.
+   * <p>
+   * This implementation checks whether {@link #isReferencesSupported(EAnnotation, EModelElement) references are supported}.
+   * If not, it checks whether the references are empty and if not {@link #reportIgnoredReferences(EAnnotation, EModelElement, Collection, DiagnosticChain, Map) reports ignored references}.
+   * If references are supported, then for each reference, it tests whether that reference is among the {@link #getValidReferences(EAnnotation, EModelElement, Collection) valid references},
+   * passing in this annotation's references to determine the valid references,
+   * and {@link #reportInvalidReference(EAnnotation, EModelElement, EObject, DiagnosticChain, Map) reports an invalid reference} for each not present in the valid references.
+   * </p>
+   * <p>
+   * It's typically the case that annotations ignore references.
+   * If that's not the case, specialize {@link #isReferencesSupported(EAnnotation, EModelElement)}
+   * and {@link #getValidReferences(EAnnotation, EModelElement, Collection)}.
+   * An implementation may override this method to report missing required references.
+   * </p>
+   * @param eAnnotation the annotation in question.
+   * @param eModelElement the annotation's {@link EAnnotation#getEModelElement() containing} model element.
+   * @param diagnostics a place to accumulate diagnostics; if it's <code>null</code>, no diagnostics should be produced.
+   * @param context a place to cache information, if it's <code>null</code>, no cache is supported.
+   * @return whether this annotation's references are valid.
+   * @see #isReferencesSupported(EAnnotation, EModelElement)
+   */
+  protected boolean validateReferences(EAnnotation eAnnotation, EModelElement eModelElement, DiagnosticChain diagnostics, Map<Object, Object> context)
+  {
+    EList<EObject> references = eAnnotation.getReferences();
+    if (!isReferencesSupported(eAnnotation, eModelElement))
+    {
+      boolean result = references.isEmpty();
+      if (!result && diagnostics != null)
+      {
+        reportIgnoredReferences(eAnnotation, eModelElement, references, diagnostics, context);
+      }
+      return result;
+    }
+    else
+    {
+      boolean result = true;
+      Collection<?> validReferences = getValidReferences(eAnnotation, eModelElement, references);
+      for (EObject reference : references)
+      {
+        if (!validReferences.contains(reference))
+        {
+          result = false;
+          if (diagnostics == null)
+          {
+            break;
+          }
+          else
+          {
+            reportInvalidReference(eAnnotation, eModelElement, reference, diagnostics, context);
+          }
+        }
+      }
+      return result;
+    }
+  }
+
+  /**
+   * Returns whether {@link EAnnotation#getReferences() references} are meaningful for this annotation.
+   * <p>
+   * This method used to determine how references should be {@link #validateReferences(EAnnotation, EModelElement, DiagnosticChain, Map) validated}.
+   * Also, an induced user interface should avoid providing the ability to specify references when this returns <code>false</code>.
+   * Implementations that override this to ever return <code>true</code> should also override {@link #getValidReferences(EAnnotation, EModelElement, Collection)} to control the valid choices.
+   * </p>
+   * @param eAnnotation the annotation in question.
+   * @param eModelElement the annotation's {@link EAnnotation#getEModelElement() containing} model element.
+   * @return whether references are meaningful for this annotation.
+   * @see Assistant#isReferencesSupported(EAnnotation)
+   * @see #validateReferences(EAnnotation, EModelElement, DiagnosticChain, Map)
+   */
+  protected boolean isReferencesSupported(EAnnotation eAnnotation, EModelElement eModelElement)
+  {
+    return false;
+  }
+
+  /**
+   * Returns the filtered collection of references that are valid for this annotation.
+   * <p>
+   * An induced user interface should provide the ability to specify only the references returned by this method.
+   * The references argument may contain all reachable objects, some subset there of, or none at all;
+   * an implementation may choose to filter from this collection or to provide its own result, including objects not in this collection.
+   * This implementation returns the references argument if {@link #isReferencesSupported(EAnnotation, EModelElement) references are supported}, or an empty list otherwise.
+   * It is also used to {@link #validateReferences(EAnnotation, EModelElement, DiagnosticChain, Map) determine} which references are valid.
+   * An implementation that overrides this should also override {@link #isReferencesSupported(EAnnotation, EModelElement)}.
+   * </p>
+   * @param eAnnotation the annotation in question.
+   * @param eModelElement the annotation's {@link EAnnotation#getEModelElement() containing} model element.
+   * @param references all reachable objects, some subset there of, or none at all.
+   * @return the objects that are valid as references for this annotation.
+   * @see Assistant#getValidReferences(EAnnotation, Collection)
+   */
+  protected Collection<?> getValidReferences(EAnnotation eAnnotation, EModelElement eModelElement, Collection<?> references)
+  {
+    return isReferencesSupported(eAnnotation, eModelElement) ? references : Collections.emptyList();
+  }
+
+  /**
+   * Returns whether this annotation's {@link EAnnotation#getContents() contents} are valid.
+   * <p>
+   * This implementation checks whether {@link #isContentsSupported(EAnnotation, EModelElement) contents are supported}.
+   * If not, it checks whether the contents are empty and if not {@link #reportIgnoredContents(EAnnotation, EModelElement, Collection, DiagnosticChain, Map) reports ignored contents}.
+   * If contents are supported, then for each content, it tests whether that content is among the {@link #getValidContents(EAnnotation, EModelElement, Collection) valid contents},
+   * passing in this annotation's contents to determine the valid contents,
+   * and {@link #reportInvalidContent(EAnnotation, EModelElement, EObject, DiagnosticChain, Map) reports an invalid content} for each not present in the valid contents.
+   * </p>
+   * <p>
+   * It's typically the case that annotations ignore contents.
+   * If that's not the case, specialize {@link #isContentsSupported(EAnnotation, EModelElement)}
+   * and {@link #getValidContents(EAnnotation, EModelElement, Collection)}.
+   * An implementation may override this method to report missing required contents.
+   * </p>
+   * @param eAnnotation the annotation in question.
+   * @param eModelElement the annotation's {@link EAnnotation#getEModelElement() containing} model element.
+   * @param diagnostics a place to accumulate diagnostics; if it's <code>null</code>, no diagnostics should be produced.
+   * @param context a place to cache information, if it's <code>null</code>, no cache is supported.
+   * @return whether this annotation's contents are valid.
+   * @see #isContentsSupported(EAnnotation, EModelElement)
+   * @see #getValidContents(EAnnotation, EModelElement, Collection)
+   */
+  protected boolean validateContents(EAnnotation eAnnotation, EModelElement eModelElement, DiagnosticChain diagnostics, Map<Object, Object> context)
+  {
+    EList<EObject> contents = eAnnotation.getContents();
+    if (!isContentsSupported(eAnnotation, eModelElement))
+    {
+      boolean result = contents.isEmpty();
+      if (!result && diagnostics != null)
+      {
+        reportIgnoredContents(eAnnotation, eModelElement, contents, diagnostics, context);
+      }
+      return result;
+    }
+    else
+    {
+      boolean result = true;
+      Collection<?> validContents = getValidContents(eAnnotation, eModelElement, contents);
+      for (EObject content : contents)
+      {
+        if (!validContents.contains(content))
+        {
+          result = false;
+          if (diagnostics == null)
+          {
+            break;
+          }
+          else
+          {
+            reportInvalidContent(eAnnotation, eModelElement, content, diagnostics, context);
+          }
+        }
+      }
+      return result;
+    }
+  }
+
+  /**
+   * Returns whether {@link EAnnotation#getContents() contents} are meaningful for this annotation.
+   * <p>
+   * This method used to determine how contents should be {@link #validateContents(EAnnotation, EModelElement, DiagnosticChain, Map) validated}.
+   * Also, an induced user interface should avoid providing the ability to specify contents when this returns <code>false</code>.
+   * Implementations that override this to ever return <code>true</code> should also override {@link #getValidContents(EAnnotation, EModelElement, Collection)} to control the valid choices.
+   * </p>
+   * @param eAnnotation the annotation in question.
+   * @param eModelElement the annotation's {@link EAnnotation#getEModelElement() containing} model element.
+   * @return whether contents are meaningful for this annotation.
+   * @see Assistant#isContentsSupported(EAnnotation)
+   * @see #validateContents(EAnnotation, EModelElement, DiagnosticChain, Map)
+   */
+  protected boolean isContentsSupported(EAnnotation eAnnotation, EModelElement eModelElement)
+  {
+    return false;
+  }
+
+  /**
+   * Returns the filtered collection of contents that are valid for this annotation.
+   * <p>
+   * An induced user interface should provide the ability to specify only the contents returned by this method.
+   * The contents argument may contain nothing at all, or the {@link EAnnotation#getContents() current contents} of the annotation;
+   * an implementation may choose to filter from this collection or to provide its own result, including objects not in this collection
+   * but it should not remove objects currently contained by the annotation that are valid.
+   * This implementation returns the contents argument if {@link #isContentsSupported(EAnnotation, EModelElement) contents are supported}, or an empty list otherwise.
+   * It is also used to {@link #validateContents(EAnnotation, EModelElement, DiagnosticChain, Map) determine} which contents are valid
+   * and should therefore <b>not</b> remove values from the provided contents argument if they are valid.
+   * An implementation that overrides this should also override {@link #isContentsSupported(EAnnotation, EModelElement)}.
+   * </p>
+   * @param eAnnotation the annotation in question.
+   * @param eModelElement the annotation's {@link EAnnotation#getEModelElement() containing} model element.
+   * @param contents nothing at all, or the {@link EAnnotation#getContents() current or potential contents} of the annotation.
+   * @return the objects that are valid as contents for this annotation.
+   * @see Assistant#getValidContents(EAnnotation, Collection)
+   */
+  protected Collection<? extends EObject> getValidContents(EAnnotation eAnnotation, EModelElement eModelElement, Collection<? extends EObject> contents)
+  {
+    return isContentsSupported(eAnnotation, eModelElement) ? contents : Collections.<EObject> emptyList();
+  }
+
+  /**
+   * Returns whether this annotation's {@link EAnnotation#getEAnnotations() nested annotations} are valid.
+   * <p>
+   * This implementation iterates over the nested annotations, and if there is at least one for which there is no {@link org.eclipse.emf.ecore.EAnnotationValidator.Registry#getEAnnotationValidator(String) registered annotation validator}
+   * or for which the registered annotation validator does not consider this nested annotation {@link #isValidLocation(EAnnotation) valid at this location},
+   * it {@link #reportIgnoredAnnotations(EAnnotation, EModelElement, Collection, DiagnosticChain, Map) reports ignored annotations}.
+   * It's typically the case that annotations ignore nested annotations.
+   * If that's not the case, you should override this method and specialize {@link #isAnnotationsSupported(EAnnotation, EModelElement)}
+   * and consider specializing {@link #getValidAnnotations(EAnnotation, EModelElement, Collection)}
+   * </p>
+   * <p>
+   * This implementation checks whether {@link #isAnnotationsSupported(EAnnotation, EModelElement) nested annotations are supported}.
+   * If not, it checks whether the {@link #getValidAnnotations(EAnnotation, EModelElement, Collection) valid annotations},
+   * passing in this annotation's nested annotations to determine the valid annotations,
+   * contain all the nested annotations; if not it {@link #reportIgnoredAnnotations(EAnnotation, EModelElement, Collection, DiagnosticChain, Map) reports ignored annotations}.
+   * If nested annotations are supported, then for each nested annotation, it tests whether that annotation is among the {@link #getValidAnnotations(EAnnotation, EModelElement, Collection) valid annotations}
+   * and {@link #reportInvalidAnnotation(EAnnotation, EModelElement, EAnnotation, DiagnosticChain, Map) reports an invalid annotation} for each not present in the valid annotations.
+   * </p>
+   * <p>
+   * It's typically the case that annotations ignore nested annotations.
+   * If that's not the case, specialize {@link #isAnnotationsSupported(EAnnotation, EModelElement)}
+   * and {@link #getValidAnnotations(EAnnotation, EModelElement, Collection)}.
+   * An implementation may override this method to report missing required nested annotations.
+   * </p>
+   * @param eAnnotation the annotation in question.
+   * @param eModelElement the annotation's {@link EAnnotation#getEModelElement() containing} model element.
+   * @param diagnostics a place to accumulate diagnostics; if it's <code>null</code>, no diagnostics should be produced.
+   * @param context a place to cache information, if it's <code>null</code>, no cache is supported.
+   * @return whether this annotation's nested annotations are valid.
+   * @see #isAnnotationsSupported(EAnnotation, EModelElement)
+   */
+  protected boolean validateAnnotations(EAnnotation eAnnotation, EModelElement eModelElement, DiagnosticChain diagnostics, Map<Object, Object> context)
+  {
+    EList<EAnnotation> annotations = eAnnotation.getEAnnotations();
+    Collection<? extends EAnnotation> validAnnotations = getValidAnnotations(eAnnotation, eModelElement, annotations);
+    if (!isAnnotationsSupported(eAnnotation, eModelElement))
+    {
+      if (!validAnnotations.containsAll(annotations))
+      {
+        if (diagnostics != null)
+        {
+          List<EAnnotation> ignoredAnnotations = new ArrayList<EAnnotation>(annotations);
+          ignoredAnnotations.removeAll(validAnnotations);
+          reportIgnoredAnnotations(eAnnotation, eModelElement, ignoredAnnotations, diagnostics, context);
+        }
+        return false;
+      }
+      else
+      {
+        return true;
+      }
+    }
+    else
+    {
+      boolean result = true;
+      for (EAnnotation nestedEAnnotation : annotations)
+      {
+        if (!validAnnotations.contains(nestedEAnnotation))
+        {
+          result = false;
+          if (diagnostics == null)
+          {
+            break;
+          }
+          else
+          {
+            reportInvalidAnnotation(eAnnotation, eModelElement, nestedEAnnotation, diagnostics, context);
+          }
+        }
+      }
+      return result;
+    }
+  }
+
+  /**
+   * Returns whether {@link EAnnotation#getEAnnotations() nested annotations} are meaningful for this annotation.
+   * <p>
+   * This method used to determine how nested annotations should be {@link #validateAnnotations(EAnnotation, EModelElement, DiagnosticChain, Map) validated}.
+   * Also, an induced user interface should avoid providing the ability to specify nested annotations when this returns <code>false</code>.
+   * Implementations that override this to ever return <code>true</code> should also override {@link #getValidAnnotations(EAnnotation, EModelElement, Collection)} to control the valid choices.
+   * </p>
+   * @param eAnnotation the annotation in question.
+   * @param eModelElement the annotation's {@link EAnnotation#getEModelElement() containing} model element.
+   * @return whether nested annotations are meaningful for this annotation.
+   * @see Assistant#isAnnotationsSupported(EAnnotation)
+   * @see #validateAnnotations(EAnnotation, EModelElement, DiagnosticChain, Map)
+   */
+  protected boolean isAnnotationsSupported(EAnnotation eAnnotation, EModelElement eModelElement)
+  {
+    return false;
+  }
+
+  /**
+   * Returns the filtered collection of nested annotations that are valid for this annotation.
+   * <p>
+   * An induced user interface should provide the ability to specify only the nested annotations returned by this method.
+   * The contents argument may contain nothing at all, or the {@link EModelElement#getEAnnotations() current nested annotations} of the specified annotation;
+   * an implementation may choose to filter from this collection or to provide its own result, including objects not in this collection,
+   * but it should <b>not</b> remove nested annotations currently contained by the annotation that are valid.
+   * This implementation takes into account the fact that annotations may be specifically designed to annotate other annotations,
+   * i.e., that the nested annotation source might correspond to a {@link org.eclipse.emf.ecore.EAnnotationValidator.Registry#getEAnnotationValidator(String) registered annotation validator}
+   * that considers its annotations {@link BasicEAnnotationValidator#isValidLocation(EAnnotation, EModelElement) valid} when contained by the specified annotation.
+   * As such, this implementation does not remove nested annotations for which there is a registered validator that considers its annotation valid in the specified annotation.
+   * Also, this implementation's result will include an additional annotation for each registered annotation validator that considers its annotations valid when nested in this annotation.
+   * This method is used to {@link #validateAnnotations(EAnnotation, EModelElement, DiagnosticChain, Map) determine} which nested annotations are valid
+   * and should therefore <b>not</b> remove values from the provided annotations argument if they are valid.
+   * In fact, an override should <b>only</b> add values to those returned by this implementation.
+   * An implementation that overrides this method should also override {@link #isAnnotationsSupported(EAnnotation, EModelElement)}.
+   * </p>
+   * @param eAnnotation the annotation in question.
+   * @param eModelElement the annotation's {@link EAnnotation#getEModelElement() containing} model element.
+   * @param annotations nothing at all, or the {@link EModelElement#getEAnnotations() current or potential nested annotations} of the annotation.
+   * @return the nested annotations that are valid as annotations for this annotation.
+   * @see Assistant#getValidAnnotations(EAnnotation, Collection)
+   */
+  protected Collection<? extends EAnnotation> getValidAnnotations(EAnnotation eAnnotation, EModelElement eModelElement, Collection<? extends EAnnotation> annotations)
+  {
+    List<EAnnotation> result = new ArrayList<EAnnotation>(annotations);
+    for (EAnnotation nestedEAnnotation : annotations)
+    {
+      EAnnotationValidator eAnnotationValidator = EAnnotationValidator.Registry.INSTANCE.getEAnnotationValidator(nestedEAnnotation.getSource());
+      if (!(eAnnotationValidator instanceof BasicEAnnotationValidator) || !((BasicEAnnotationValidator)eAnnotationValidator).isValidLocation(nestedEAnnotation, eAnnotation))
+      {
+        result.remove(nestedEAnnotation);
+      }
+    }
+    for (String annotationSource : EAnnotationValidator.Registry.INSTANCE.keySet())
+    {
+      EAnnotationValidator eAnnotationValidator = EAnnotationValidator.Registry.INSTANCE.getEAnnotationValidator(annotationSource);
+      if (eAnnotationValidator instanceof BasicEAnnotationValidator)
+      {
+        BasicEAnnotationValidator basicEAnnotationValidator = (BasicEAnnotationValidator)eAnnotationValidator;
+        EAnnotation nestedEAnnotation = EcoreFactory.eINSTANCE.createEAnnotation();
+        nestedEAnnotation.setSource(annotationSource);
+        EAnnotation otherEAnnotation = eAnnotation.getEAnnotation(annotationSource);
+        if ((otherEAnnotation == null || basicEAnnotationValidator.isDuplicateValid(eAnnotation, otherEAnnotation, nestedEAnnotation))
+          && ((BasicEAnnotationValidator)eAnnotationValidator).isValidLocation(nestedEAnnotation, eAnnotation))
+        {
+          result.add(nestedEAnnotation);
+        }
+      }
+    }
+    return result;
+  }
+
+  /**
+   * Returns whether this annotation's {@link EAnnotation#getDetails() details} are valid.
+   * <p>
+   * This implementation uses the {@link #getProperties(EModelElement) properties of the model element}.
+   * For each detail, it determines whether there is a corresponding feature in the properties.
+   * If not, it validates the detail {@link #validateDetail(EAnnotation, EModelElement, java.util.Map.Entry, DiagnosticChain, Map) without a property feature}.
+   * If so, it validates the detail {@link #validateFeatureDetail(EAnnotation, EModelElement, java.util.Map.Entry, EStructuralFeature, DiagnosticChain, Map) with the property feature}.
+   * If all the details are valid,
+   * it will check whether any {@link EStructuralFeature#isRequired() required} property feature is absent from the details
+   * and {@link #reportMissingEntry(EAnnotation, EModelElement, String, EStructuralFeature, DiagnosticChain, Map) reports it missing}.
+   * </p>
+   * @param eAnnotation the annotation in question.
+   * @param eModelElement the annotation's {@link EAnnotation#getEModelElement() containing} model element.
+   * @param diagnostics a place to accumulate diagnostics; if it's <code>null</code>, no diagnostics should be produced.
+   * @param context a place to cache information, if it's <code>null</code>, no cache is supported.
+   * @return whether this annotation's details are valid.
+   */
+  protected boolean validateDetails(EAnnotation eAnnotation, EModelElement eModelElement, DiagnosticChain diagnostics, Map<Object, Object> context)
+  {
+    boolean result = false;
+    Map<String, EStructuralFeature> properties = new LinkedHashMap<String, EStructuralFeature>(getProperties(eModelElement));
+    for (Map.Entry<String, String> entry : eAnnotation.getDetails())
+    {
+      String key = entry.getKey();
+      EStructuralFeature feature = properties.remove(key);
+      if (feature == null)
+      {
+        result &= validateDetail(eAnnotation, eModelElement, entry, diagnostics, context);
+      }
+      else
+      {
+        result &= validateFeatureDetail(eAnnotation, eModelElement, entry, feature, diagnostics, context);
+      }
+      if (!result && diagnostics == null)
+      {
+        return false;
+      }
+    }
+
+    if (result)
+    {
+      for (Map.Entry<String, EStructuralFeature> entry : properties.entrySet())
+      {
+        EStructuralFeature feature = entry.getValue();
+        if (feature.isRequired())
+        {
+          result = false;
+          if (diagnostics == null)
+          {
+            break;
+          }
+          else
+          {
+            reportMissingEntry(eAnnotation, eModelElement, entry.getKey(), feature, diagnostics, context);
+          }
+        }
+      }
+    }
+
+    return result;
+  }
+
+  /**
+   * Returns a map from key to {@link EStructuralFeature feature}.
+   * These represents the keys that are considered valid and can be processed by this annotation validator.
+   * <p>
+   * This implementation uses {@link #getPropertyClasses(EModelElement)}, iterating over each class and each feature of each class, adding to the map each {@link #isIncludedProperty(EModelElement, EClass, EStructuralFeature) included} feature.
+   * If that method returns an empty list, then implementation returns an empty map.
+   * In that case, {@link #validateDetails(EAnnotation, EModelElement, DiagnosticChain, Map) validating the details} of any annotation will report all detail entries as being ignored.
+   * An annotation validator implement must override either this method, the <code>getPropertyClasses</code> method or the <code>validateDetails</code> method.
+   * </p>
+   * @param eModelElement the model element that is being annotated.
+   * @return a map from key to feature.
+   * @see #validateDetails(EAnnotation, EModelElement, DiagnosticChain, Map)
+   * @see #getPropertyClasses(EModelElement)
+   */
+  protected Map<String, EStructuralFeature> getProperties(EModelElement eModelElement)
+  {
+    Map<String, EStructuralFeature> properties = new LinkedHashMap<String, EStructuralFeature>();
+    for (EClass eClass : getPropertyClasses(eModelElement))
+    {
+      for (EStructuralFeature eStructuralFeature : eClass.getEAllStructuralFeatures())
+      {
+        if (isIncludedProperty(eModelElement, eClass, eStructuralFeature))
+        {
+          properties.put(eStructuralFeature.getName(), eStructuralFeature);
+        }
+      }
+    }
+    return Collections.unmodifiableMap(properties);
+  }
+
+  /**
+   * Returns whether the given structural feature of the given class for the given model element is {@link #getProperties(EModelElement) included as a property}.
+   * @param eModelElement the model element.
+   * @param eClass the class used to model the annotation for the model element.
+   * @param eStructuralFeature a structural feature of the class.
+   * @return whether the given structural feature of the given class for the given model element is included as a property.
+   */
+  protected boolean isIncludedProperty(EModelElement eModelElement, EClass eClass, EStructuralFeature eStructuralFeature)
+  {
+    return true;
+  }
+
+  /**
+   * Creates an instance of the modeled representation for the given annotation.
+   * <p>
+   * This implementation {@link EcoreUtil#create(EClass) creates} an instance and {@link #initialize(EObject, EAnnotation) initializes} it.
+   * </p>
+   * @param eClass the class to be instantiated.
+   * @param eAnnotation the annotation with the information that needs to be represented.
+   * @return creates an instance of the modeled representation for the given annotation.
+   */
+  protected EObject createInstance(EClass eClass, EAnnotation eAnnotation)
+  {
+    EModelElement eModelElement = eAnnotation.getEModelElement();
+    if (!getPropertyClasses(eModelElement).contains(eClass))
+    {
+      throw new IllegalArgumentException("The eClass is not a property class of the model element");
+    }
+    else
+    {
+      return initialize(EcoreUtil.create(eClass), eAnnotation);
+    }
+  }
+
+  /**
+   * Returns an initialized instance of the given object for the given annotation.
+   * <p>
+   * This implementation handles only the case of modeled attributes.
+   * For each {@link EAnnotation#getDetails() detail entry},
+   * it looks up the corresponding {@link #getProperties(EModelElement) property} via the key.
+   * If it's not an {@link EAttribute} it will throw an {@link UnsupportedOperationException}.
+   * If the attribute property is {@link EStructuralFeature#isMany() multi-valued},
+   * it {@link #split(EAnnotation, EModelElement, Map.Entry, String, EStructuralFeature, DiagnosticChain, Map) splits} the detail entry value, and {@link EcoreUtil#convertToString(EDataType, Object) converts} each literal item into a value of the {@link EAttribute#getEAttributeType() attribute's data type}.
+   * If it's single-valued, the literal value is directly converted to the attributes data type.
+   * The resulting list value or single value is {@link EObject#eSet(EStructuralFeature, Object) reflectively set} into the instance.
+   * If the model representation includes references,
+   * an annotation validator implementation must specialize this method for the {@link Assistant#createInstance(EClass, EAnnotation) assistant} to function correctly.
+   * </p>
+   * @param eObject the object to initialize.
+   * @param eAnnotation the annotation used to initialize the object.
+   * @return an initialized instance.
+   */
+  protected EObject initialize(EObject eObject, EAnnotation eAnnotation)
+  {
+    EModelElement eModelElement = eAnnotation.getEModelElement();
+    Map<String, EStructuralFeature> properties = getProperties(eModelElement);
+    for (Map.Entry<String, String> entry : eAnnotation.getDetails())
+    {
+      String key = entry.getKey();
+      EStructuralFeature eStructuralFeature = properties.get(key);
+      if (eStructuralFeature instanceof EAttribute)
+      {
+        EDataType eDataType = (EDataType)eStructuralFeature.getEType();
+        String literalValue = entry.getValue();
+        if (eStructuralFeature.isMany())
+        {
+          List<String> literalValues = split(eAnnotation, eModelElement, entry, literalValue, eStructuralFeature, null, null);
+          List<Object> value = new ArrayList<Object>();
+          if (literalValues != null)
+          {
+            for (String itemLiteralValue : literalValues)
+            {
+              value.add(EcoreUtil.createFromString(eDataType, itemLiteralValue));
+            }
+          }
+          eObject.eSet(eStructuralFeature, value);
+        }
+        else
+        {
+          eObject.eSet(eStructuralFeature, EcoreUtil.createFromString(eDataType, literalValue));
+        }
+      }
+      else if (eStructuralFeature != null)
+      {
+        throw new UnsupportedOperationException("Initializing of references is not supported");
+      }
+    }
+    return eObject;
+  }
+
+  /**
+   * Returns the value of the feature of the modeled object converted to a literal representation as used in {@link EAnnotation#getDetails() detail entry}.
+   * <p>
+   * This implementation handles both {@link EAttribute} and {@link EReference}.
+   * For a {@link EStructuralFeature#isMany() multi-valued} feature, it {@link #convertPropertyReferenceValueToLiteralItem(EObject, EReference, Object) converts} for each item in the list, and {@link #join(EObject, EStructuralFeature, List) joins} them into a single string.
+   * For a single-valued feature, it returns the {@link #convertPropertyReferenceValueToLiteralItem(EObject, EReference, Object) converted} value.
+   * This method is not used by the validator but is useful for specializing the {@link Assistant#convertPropertyValueToLiteral(EObject, EStructuralFeature, Object)}.
+   * </p>
+   * @param eObject the modeled object.
+   * @param eStructuralFeature a feature of that object.
+   * @param value the value to converted to a literal representation.
+   * @return the value of the feature of the modeled object converted to a literal representation.
+   * @see #convertPropertyValueToLiteralItem(EObject, EStructuralFeature, Object)
+   */
+  protected String convertPropertyValueToLiteral(EObject eObject, EStructuralFeature eStructuralFeature, Object value)
+  {
+    if (eStructuralFeature.isMany())
+    {
+      List<String> result = new ArrayList<String>();
+      if (value != null)
+      {
+        @SuppressWarnings("unchecked")
+        List<Object> values = (List<Object>)value;
+        for (Object valueItem : values)
+        {
+          result.add(convertPropertyValueToLiteralItem(eObject, eStructuralFeature, valueItem));
+        }
+      }
+      return join(eObject, eStructuralFeature, result);
+    }
+    else
+    {
+      return convertPropertyValueToLiteralItem(eObject, eStructuralFeature, value);
+    }
+  }
+
+  /**
+   * Returns the single value of the feature's {@link ETypedElement#getEType() type} for the modeled object converted to a literal representation as used in {@link EAnnotation#getDetails() detail entry}.
+   * <p>
+   * This implementation delegates to {@link #convertPropertyAttributeValueToLiteralItem(EObject, EAttribute, Object)} or {@link #convertPropertyReferenceValueToLiteralItem(EObject, EReference, Object)} as appropriate.
+   * </p>
+   * @param eObject the modeled object.
+   * @param eStructuralFeature a feature of that object.
+   * @param value the value of the feature's type to converted to a literal representation.
+   * @return a value of the feature's type converted to a literal representation.
+   * @see #convertPropertyValueToLiteral(EObject, EStructuralFeature, Object)
+   */
+  protected String convertPropertyValueToLiteralItem(EObject eObject, EStructuralFeature eStructuralFeature, Object value)
+  {
+    if (eStructuralFeature instanceof EAttribute)
+    {
+      return convertPropertyAttributeValueToLiteralItem(eObject, (EAttribute)eStructuralFeature, value);
+    }
+    else
+    {
+      return convertPropertyReferenceValueToLiteralItem(eObject, (EReference)eStructuralFeature, value);
+    }
+  }
+
+  /**
+   * Returns the single value of the attribute's {@link ETypedElement#getEType() type} for the modeled object converted to a literal representation as used in {@link EAnnotation#getDetails() detail entry}.
+   * <p>
+   * This implementation simple uses {@link EcoreUtil#convertToString(EDataType, Object)}.
+   * </p>
+   * @param eObject the modeled object.
+   * @param eAttribute an attribute feature of that object.
+   * @param value the value of the feature's type to converted to a literal representation.
+   * @return a value of the feature's type converted to a literal representation.
+   * @see #convertPropertyValueToLiteral(EObject, EStructuralFeature, Object)
+   */
+  protected String convertPropertyAttributeValueToLiteralItem(EObject eObject, EAttribute eAttribute, Object value)
+  {
+    return EcoreUtil.convertToString(eAttribute.getEAttributeType(), value);
+  }
+
+  /**
+   * Returns the single value of the references's {@link ETypedElement#getEType() type} for the modeled object converted to a literal representation as used in {@link EAnnotation#getDetails() detail entry}.
+   * <p>
+   * This implementation is incomplete.
+   * It can't generally be known how to represent a reference to an object.
+   * This implementation looks for a feature called "name", {@link EObject#eGet(EStructuralFeature) gets} the value, and if it's a string returns it.
+   * Failing that, it throws an {@link UnsupportedOperationException}.
+   * </p>
+   * @param eObject the modeled object.
+   * @param eReference a reference feature of that object.
+   * @param value the value of the reference's type to converted to a literal representation.
+   * @return a value of the references's type converted to a literal representation.
+   * @see #convertPropertyValueToLiteral(EObject, EStructuralFeature, Object)
+   */
+  protected String convertPropertyReferenceValueToLiteralItem(EObject eObject, EReference eReference, Object value)
+  {
+    if (value == null)
+    {
+      return null;
+    }
+    else if (value instanceof EObject)
+    {
+      EObject valueEObject = (EObject)value;
+      EStructuralFeature eStructuralFeature = valueEObject.eClass().getEStructuralFeature("name");
+      if (eStructuralFeature != null)
+      {
+        Object name = valueEObject.eGet(eStructuralFeature);
+        if (name instanceof String)
+        {
+          return name.toString();
+        }
+      }
+    }
+
+    throw new UnsupportedOperationException("Unable to convert '" + value + "' to a literal value for feature " + eReference + " of " + eObject);
+  }
+
+  /**
+   * Returns the joined list of values of this modeled object's feature.
+   * <p>
+   * This implementation simply separates the individual literal value items with a " ".
+   * </p>
+   * @param eObject the modeled object.
+   * @param eStructuralFeature a feature of that object.
+   * @param literalValues the literal value to join into a single value.
+   * @return
+   */
+  protected String join(EObject eObject, EStructuralFeature eStructuralFeature, List<String> literalValues)
+  {
+    return XMLTypeFactory.eINSTANCE.convertENTITIESBase(literalValues);
+  }
+
+  /**
+   * Returns whether the given feature of the given modeled representation is meaningful for the current state of the model.
+   * <p>
+   * This method is used to induce the {@link Assistant#getApplicableProperties(EObject, EAnnotation) applicable properties} by the assistant.
+   * It is not directly used by the annotation validator itself.
+   * This implementation always returns <code>true</code>.
+   * </p>
+   * @param eObject the modeled object in question.
+   * @param eStructuralFeature a feature of that object.
+   * @return whether the given feature of the given modeled representation is meaningful for the current state of the model.
+   */
+  protected boolean isApplicable(EObject eObject, EStructuralFeature eStructuralFeature)
+  {
+    return true;
+  }
+
+  /**
+   * Returns whether this detail entry is valid.
+   * <p>
+   * This method is only called when there is no {@link #getProperties(EModelElement) property} associated with this entry's {@link java.util.Map.Entry#getKey() key}.
+   * This implementation always {@link #reportIgnoredEntry(EAnnotation, EModelElement, Map.Entry, DiagnosticChain, Map) reports an ignored entry}.
+   * An annotation validator implementation may choose to support validation by specializing this method, rather than {@link #getPropertyClasses(EModelElement) providing a modeled representation},
+   * but the {@link Assistant assistant} will not provide any useful support.
+   * </p>
+   * @param eAnnotation the annotation in question.
+   * @param eModelElement the annotation's {@link EAnnotation#getEModelElement() containing} model element.
+   * @param entry the annotation {@link EAnnotation#getDetails() detail} in question.
+   * @param diagnostics a place to accumulate diagnostics; if it's <code>null</code>, no diagnostics should be produced.
+   * @param context a place to cache information, if it's <code>null</code>, no cache is supported.
+   * @return whether this detail entry is valid.
+   */
+  protected boolean validateDetail(EAnnotation eAnnotation, EModelElement eModelElement, Map.Entry<String, String> entry, DiagnosticChain diagnostics, Map<Object, Object> context)
+  {
+    if (diagnostics != null)
+    {
+      reportIgnoredEntry(eAnnotation, eModelElement, entry, diagnostics, context);
+    }
+    return false;
+  }
+
+  /**
+   * Returns whether the value of this detail entry for the corresponding feature is valid.
+   * <p>
+   * This implementation delegates
+   * to {@link #validateAttributeDetailLiteralValue(EAnnotation, EModelElement, java.util.Map.Entry, EAttribute, List, DiagnosticChain, Map)  validateAttributeDetail}
+   * or to {@link #validateReferenceDetailLiteralValue(EAnnotation, EModelElement, Map.Entry, EReference, List, DiagnosticChain, Map)  validateReferenceDetail}
+   * depending on whether the feature is an {@link EAttribute} or an {@link EReference}.
+   * It {@link #createValueDiagnostic(EAnnotation, EModelElement, java.util.Map.Entry, EStructuralFeature) creates} a place holder diagnostic that it passed to those methods,
+   * so all diagnostics gathered by those methods are grouped as {@link Diagnostic#getChildren() children} of the placeholder.
+   * Both those methods build the corresponding modeled values as a side-effect.
+   * If the detail entry is otherwise valid,
+   * the modeled value {@link #validateFeatureDetailValue(EAnnotation, EModelElement, java.util.Map.Entry, EStructuralFeature, List, DiagnosticChain, Map) is validated}.
+   * </p>
+   * @param eAnnotation the annotation in question.
+   * @param eModelElement the annotation's {@link EAnnotation#getEModelElement() containing} model element.
+   * @param entry the annotation {@link EAnnotation#getDetails() detail} in question.
+   * @param feature the {@link #getProperties(EModelElement) property} associated with entry.
+   * @param diagnostics a place to accumulate diagnostics; if it's <code>null</code>, no diagnostics should be produced.
+   * @param context a place to cache information, if it's <code>null</code>, no cache is supported.
+   * @return whether the value of this detail entry for the corresponding feature is valid.
+   */
+  protected boolean validateFeatureDetail(
+    EAnnotation eAnnotation,
+    EModelElement eModelElement,
+    Map.Entry<String, String> entry,
+    EStructuralFeature feature,
+    DiagnosticChain diagnostics,
+    Map<Object, Object> context)
+  {
+    BasicDiagnostic badValueDiagnostic = diagnostics == null ? null : createValueDiagnostic(eAnnotation, eModelElement, entry, feature);
+    List<Object> values = new ArrayList<Object>();
+    boolean result = feature instanceof EAttribute
+      ? validateAttributeDetailLiteralValue(eAnnotation, eModelElement, entry, (EAttribute)feature, values, badValueDiagnostic, context)
+      : validateReferenceDetailLiteralValue(eAnnotation, eModelElement, entry, (EReference)feature, values, badValueDiagnostic, context);
+    if (result)
+    {
+      result &= validateFeatureDetailValue(eAnnotation, eModelElement, entry, feature, values, badValueDiagnostic, context);
+    }
+    if (!result && diagnostics != null)
+    {
+      diagnostics.add(badValueDiagnostic);
+    }
+    return result;
+  }
+
+  /**
+   * Returns whether the modeled values for this detail entry's corresponding feature are valid.
+   * <p>
+   * For a {@link EStructuralFeature#isMany() many-valued} feature, it validates that the {@link EStructuralFeature#getLowerBound() lower} and {@link EStructuralFeature#getUpperBound() upper} bounds are respected.
+   * For a singled valued feature that is {@link EStructuralFeature#isRequired() required}, it validates that the value is present;
+   * in the single-valued case, the values list should contain a single value.
+   * </p>
+   * @param eAnnotation the annotation in question.
+   * @param eModelElement the annotation's {@link EAnnotation#getEModelElement() containing} model element.
+   * @param entry the annotation {@link EAnnotation#getDetails() detail} in question.
+   * @param feature the {@link #getProperties(EModelElement) property} associated with entry.
+   * @param values the list of instance values for this entry.
+   * @param diagnostics a place to accumulate diagnostics; if it's <code>null</code>, no diagnostics should be produced.
+   * @param context a place to cache information, if it's <code>null</code>, no cache is supported.
+   * @return whether the modeled values for this detail entry's corresponding feature are valid.
+   */
+  protected boolean validateFeatureDetailValue(
+    EAnnotation eAnnotation,
+    EModelElement eModelElement,
+    Map.Entry<String, String> entry,
+    EStructuralFeature feature,
+    List<Object> values,
+    DiagnosticChain diagnostics,
+    Map<Object, Object> context)
+  {
+    boolean result = true;
+    int size = values.size();
+    if (feature.isMany())
+    {
+      int lowerBound = feature.getLowerBound();
+      if (lowerBound > 0 && size < lowerBound)
+      {
+        if (diagnostics != null)
+        {
+          reportTooFewValues(eAnnotation, eModelElement, entry, feature, values, size, lowerBound, diagnostics, context);
+        }
+        result = false;
+      }
+      int upperBound = feature.getUpperBound();
+      if (upperBound > 0 && size > upperBound)
+      {
+        if (diagnostics != null)
+        {
+          reportTooManyValues(eAnnotation, eModelElement, entry, feature, values, size, upperBound, diagnostics, context);
+        }
+        result = false;
+      }
+    }
+    else
+    {
+      if (feature.isRequired())
+      {
+        if (size != 0 || values.get(0) == null)
+        {
+          result = false;
+          if (diagnostics != null)
+          {
+            reportMissingRequiredEntryValue(eAnnotation, eModelElement, feature, values, diagnostics, context);
+          }
+        }
+      }
+    }
+    return result;
+  }
+
+  /**
+   * Returns whether the literal value of this detail entry for the corresponding attribute is valid.
+   * <p>
+   * This implementation,
+   * for a {@link EStructuralFeature#isMany() many-valued} attribute,
+   * {@link #split(EAnnotation, EModelElement, Map.Entry, String, EStructuralFeature, DiagnosticChain, Map) splits} the detail value, if present, into a list of literal values
+   * and {@link #validateAttributeDetailValueLiteral(EAnnotation, EModelElement, Map.Entry, EAttribute, String, List, DiagnosticChain, Map) validates each literal value}.
+   * For a single-valued attribute, it {@link #validateAttributeDetailValueLiteral(EAnnotation, EModelElement, Map.Entry, EAttribute, String, List, DiagnosticChain, Map) directly validates} the literal value.
+   * As a side-effect, each literal value of a many-valued attribute, or the literal value of a single-valued attribute,
+   * is converted to an instance of the attribute's {@link EAttribute#getEAttributeType() data type} and is added to the data values list.
+   * </p>
+   * @param eAnnotation the annotation in question.
+   * @param eModelElement the annotation's {@link EAnnotation#getEModelElement() containing} model element.
+   * @param entry the annotation {@link EAnnotation#getDetails() detail} in question.
+   * @param attribute feature the {@link EAttribute attribute} {@link #getProperties(EModelElement) property} associated with entry.
+   * @param dataValues the list in which to accumulate valid instance values.
+   * @param diagnostics a place to accumulate diagnostics; if it's <code>null</code>, no diagnostics should be produced.
+   * @param context a place to cache information, if it's <code>null</code>, no cache is supported.
+   * @return whether the literal value of this detail entry for the corresponding attribute is valid.
+   *
+   * @see #validateAttributeDetailValueLiteral(EAnnotation, EModelElement, Map.Entry, EAttribute, String, List, DiagnosticChain, Map)
+   */
+  protected boolean validateAttributeDetailLiteralValue(
+    EAnnotation eAnnotation,
+    EModelElement eModelElement,
+    Map.Entry<String, String> entry,
+    EAttribute attribute,
+    List<Object> dataValues,
+    DiagnosticChain diagnostics,
+    Map<Object, Object> context)
+  {
+    boolean result = true;
+    String literalValue = entry.getValue();
+    if (attribute.isMany())
+    {
+      List<String> literalValues = split(eAnnotation, eModelElement, entry, literalValue, attribute, diagnostics, context);
+      if (literalValues != null)
+      {
+        for (String literalValueItem : literalValues)
+        {
+          result &= validateAttributeDetailValueLiteral(eAnnotation, eModelElement, entry, attribute, literalValueItem, dataValues, diagnostics, context);
+          if (!result && diagnostics == null)
+          {
+            break;
+          }
+        }
+      }
+    }
+    else
+    {
+      result = validateAttributeDetailValueLiteral(eAnnotation, eModelElement, entry, attribute, literalValue, dataValues, diagnostics, context);
+    }
+    return result;
+  }
+
+  /**
+   * Returns whether the given literal value is valid with respect to this detail entry's corresponding attribute's {@link EAttribute#getEAttributeType() data type}.
+   * As a side-effect, if the literal value can be converted to an instance value, the corresponding instance value is added to the list of data values.
+   * <p>
+   * This implementation first tries to {@link EcoreUtil#createFromString(EDataType, String) convert} the literal value to an instance value of the data type.
+   * If that fails, it creates a diagnostic that includes the exception {@link Exception#getLocalizedMessage() message}.
+   * Otherwise, it adds the instance value to the list of values
+   * and {@link EValidator#validate(EDataType, Object, DiagnosticChain, Map) validates} the instance value.
+   * </p>
+   * @param eAnnotation the annotation in question.
+   * @param eModelElement the annotation's {@link EAnnotation#getEModelElement() containing} model element.
+   * @param entry the annotation {@link EAnnotation#getDetails() detail} in question.
+   * @param attribute feature the {@link EAttribute attribute} {@link #getProperties(EModelElement) property} associated with entry.
+   * @param literalValue the literal value of the data type.
+   * @param dataValues the list in which to accumulate a valid instance value.
+   * @param diagnostics a place to accumulate diagnostics; if it's <code>null</code>, no diagnostics should be produced.
+   * @param context a place to cache information, if it's <code>null</code>, no cache is supported.
+   * @return whether the given literal value is valid with respect to this detail entry's corresponding attribute's data type.
+   */
+  protected boolean validateAttributeDetailValueLiteral(
+    EAnnotation eAnnotation,
+    EModelElement eModelElement,
+    Map.Entry<String, String> entry,
+    EAttribute attribute,
+    String literalValue,
+    List<Object> dataValues,
+    DiagnosticChain diagnostics,
+    Map<Object, Object> context)
+  {
+    EDataType dataType = attribute.getEAttributeType();
+    boolean result;
+    try
+    {
+      Object value = EcoreUtil.createFromString(dataType, literalValue);
+      dataValues.add(value);
+      EValidator rootEValidator = getRootEValidator(context);
+      result = rootEValidator == null || rootEValidator.validate(dataType, value, diagnostics, context);
+    }
+    catch (RuntimeException exception)
+    {
+      result = false;
+      if (diagnostics != null)
+      {
+        reportInvalidValueLiteral(eAnnotation, eModelElement, entry, attribute, literalValue, dataType, diagnostics, exception, context);
+      }
+    }
+    return result;
+  }
+
+  /**
+   * Returns whether the literal value of this detail entry for the corresponding reference is valid.
+   * <p>
+   * This implementation,
+   * for a {@link EStructuralFeature#isMany() many-valued} reference,
+   * {@link #split(EAnnotation, EModelElement, Map.Entry, String, EStructuralFeature, DiagnosticChain, Map) splits} the detail value, if present, into a list of literal values
+   * and {@link #validateReferenceDetailValueLiteral(EAnnotation, EModelElement, Map.Entry, EReference, String, List, DiagnosticChain, Map) validates each literal value}.
+   * For a single-valued attribute, it {@link #validateReferenceDetailValueLiteral(EAnnotation, EModelElement, Map.Entry, EReference, String, List, DiagnosticChain, Map) directly validates} the literal value.
+   * As a side-effect, each literal value of a many-valued reference, or the literal value of a single-valued reference,
+   * is converted to an instance of the references's {@link EReference#getEReferenceType() class} and added to the reference values list.
+   * </p>
+   * @param eAnnotation the annotation in question.
+   * @param eModelElement the annotation's {@link EAnnotation#getEModelElement() containing} model element.
+   * @param entry the annotation {@link EAnnotation#getDetails() detail} in question.
+   * @param reference the {@link EReference reference} {@link #getProperties(EModelElement) property} associated with entry.
+   * @param referenceValues the list in which to accumulate valid instance values.
+   * @param diagnostics a place to accumulate diagnostics; if it's <code>null</code>, no diagnostics should be produced.
+   * @param context a place to cache information, if it's <code>null</code>, no cache is supported.
+   * @return whether the literal value of this detail entry for the corresponding reference is valid.
+   */
+  protected boolean validateReferenceDetailLiteralValue(
+    EAnnotation eAnnotation,
+    EModelElement eModelElement,
+    Map.Entry<String, String> entry,
+    EReference reference,
+    List<Object> referenceValues,
+    DiagnosticChain diagnostics,
+    Map<Object, Object> context)
+  {
+    boolean result = true;
+    String literalValue = entry.getValue();
+    if (reference.isMany())
+    {
+      List<String> literalValues = split(eAnnotation, eModelElement, entry, literalValue, reference, diagnostics, context);
+      if (literalValues != null)
+      {
+        for (String literalValueItem : literalValues)
+        {
+          result &= validateReferenceDetailValueLiteral(eAnnotation, eModelElement, entry, reference, literalValueItem, referenceValues, diagnostics, context);
+          if (!result && diagnostics == null)
+          {
+            break;
+          }
+        }
+      }
+    }
+    else
+    {
+      result = validateReferenceDetailValueLiteral(eAnnotation, eModelElement, entry, reference, literalValue, referenceValues, diagnostics, context);
+    }
+    return result;
+  }
+
+  /**
+   * Returns whether the given literal value is valid with respect to this detail entry's corresponding reference's {@link EReference#getEReferenceType() class}.
+   * As a side-effect, if the literal value can be converted to an instance value, the corresponding instance value is added to the list of reference values.
+   * <p>
+   * This implementation always returns <code>false</code> and {@link #reportInvalidReferenceLiteral(EAnnotation, EModelElement, Map.Entry, EReference, String, DiagnosticChain, Map) reports an invalid reference literal}.
+   * An annotation validator implementation that supports reference literals must specialize this method.
+   * </p>
+   * @param eAnnotation the annotation in question.
+   * @param eModelElement the annotation's {@link EAnnotation#getEModelElement() containing} model element.
+   * @param entry the annotation {@link EAnnotation#getDetails() detail} in question.
+   * @param reference the {@link EReference reference} {@link #getProperties(EModelElement) property} associated with entry.
+   * @param literalValue the literal value of the class.
+   * @param referenceValues the list in which to accumulate valid instance values.
+   * @param diagnostics a place to accumulate diagnostics; if it's <code>null</code>, no diagnostics should be produced.
+   * @param context a place to cache information, if it's <code>null</code>, no cache is supported.
+   * @return whether the given literal value is valid with respect to this detail entry's corresponding references's class.
+   */
+  protected boolean validateReferenceDetailValueLiteral(
+    EAnnotation eAnnotation,
+    EModelElement eModelElement,
+    Map.Entry<String, String> entry,
+    EReference reference,
+    String literalValue,
+    List<Object> referenceValues,
+    DiagnosticChain diagnostics,
+    Map<Object, Object> context)
+  {
+    if (diagnostics != null)
+    {
+      reportInvalidReferenceLiteral(eAnnotation, eModelElement, entry, reference, literalValue, diagnostics, context);
+    }
+    return false;
+  }
+
+  /**
+   * Splits the literal value into a list of literal values as appropriate for this feature.
+   * <p>
+   * This implementation splits the values at whitespace boundaries for all features..
+   * </p>
+   * @param eAnnotation the annotation in question.
+   * @param eModelElement the annotation's {@link EAnnotation#getEModelElement() containing} model element.
+   * @param entry the annotation {@link EAnnotation#getDetails() detail} in question.
+   * @param literalValue a literal value of this feature's {@link EStructuralFeature#getEType() type}.
+   * @param feature the {@link #getProperties(EModelElement) property} associated with entry.
+   * @param diagnostics a place to accumulate diagnostics; if it's <code>null</code>, no diagnostics should be produced.
+   * @param context a place to cache information, if it's <code>null</code>, no cache is supported.
+   * @return splits the literal value into a list of literal values as appropriate for this feature.
+   *
+   * @see #validateAttributeDetailValueLiteral(EAnnotation, EModelElement, Map.Entry, EAttribute, String, List, DiagnosticChain, Map)
+   * @see #validateReferenceDetailValueLiteral(EAnnotation, EModelElement, Map.Entry, EReference, String, List, DiagnosticChain, Map)
+   */
+  protected List<String> split(
+    EAnnotation eAnnotation,
+    EModelElement eModelElement,
+    Map.Entry<String, String> entry,
+    String literalValue,
+    EStructuralFeature feature,
+    DiagnosticChain diagnostics,
+    Map<Object, Object> context)
+  {
+    return XMLTypeFactory.eINSTANCE.createENTITIESBase(literalValue);
+  }
+
+  /**
+   * @see #INVALID_REFERENCE_LITERAL
+   */
+  protected void reportInvalidReferenceLiteral(
+    EAnnotation eAnnotation,
+    EModelElement eModelElement,
+    Map.Entry<String, String> entry,
+    EReference reference,
+    String literalValue,
+    DiagnosticChain diagnostics,
+    Map<Object, Object> context)
+  {
+    diagnostics.add(
+      createDiagnostic(
+        Diagnostic.WARNING,
+        INVALID_REFERENCE_LITERAL,
+        getString(
+          getEcoreResourceLocator(),
+          "_UI_InvalidValue_diagnostic",
+          literalValue,
+          getString(getEcoreResourceLocator(), "_UI_InvalidReferenceValue_substitution", reference.getEReferenceType().getName())),
+        literalValue,
+        reference.getEReferenceType()));
+  }
+
+  /**
+   * @see #INVALID_VALUE_LITERAL
+   */
+  protected void reportInvalidValueLiteral(
+    EAnnotation eAnnotation,
+    EModelElement eModelElement,
+    Map.Entry<String, String> entry,
+    EAttribute attribute,
+    String literalValue,
+    EDataType dataType,
+    DiagnosticChain diagnostics,
+    RuntimeException exception,
+    Map<Object, Object> context)
+  {
+    diagnostics.add(
+      createDiagnostic(
+        Diagnostic.WARNING,
+        INVALID_VALUE_LITERAL,
+        getString(getEcoreResourceLocator(), "_UI_InvalidValue_diagnostic", literalValue, exception.getLocalizedMessage()),
+        literalValue,
+        dataType));
+  }
+
+  /**
+   * @see #MISSING_REQUIRED_ENTRY_VALUE
+   */
+  protected void reportMissingRequiredEntryValue(
+    EAnnotation eAnnotation,
+    EModelElement eModelElement,
+    EStructuralFeature feature,
+    List<Object> values,
+    DiagnosticChain diagnostics,
+    Map<Object, Object> context)
+  {
+    diagnostics.add(
+      createDiagnostic(
+        Diagnostic.WARNING,
+        MISSING_REQUIRED_ENTRY_VALUE,
+        getString(getEcoreResourceLocator(), "_UI_InvalidValueRequiredFeatureMustBeSet_diagnostic"),
+        (Object)null));
+  }
+
+  /**
+   * @see #TOO_FEW_VALUES
+   */
+  protected void reportTooFewValues(
+    EAnnotation eAnnotation,
+    EModelElement eModelElement,
+    Map.Entry<String, String> entry,
+    EStructuralFeature feature,
+    List<Object> values,
+    int size,
+    int lowerBound,
+    DiagnosticChain diagnostics,
+    Map<Object, Object> context)
+  {
+    diagnostics.add(
+      createDiagnostic(Diagnostic.WARNING, TOO_FEW_VALUES, getString(getEcoreResourceLocator(), "_UI_InvalidValueFeatureHasTooFewValues_diagnostic", size, lowerBound), values));
+  }
+
+  /**
+   * @see #TOO_MANY_VALUES
+   */
+  protected void reportTooManyValues(
+    EAnnotation eAnnotation,
+    EModelElement eModelElement,
+    Map.Entry<String, String> entry,
+    EStructuralFeature feature,
+    List<Object> values,
+    int size,
+    int upperBound,
+    DiagnosticChain diagnostics,
+    Map<Object, Object> context)
+  {
+    diagnostics.add(
+      createDiagnostic(Diagnostic.WARNING, TOO_MANY_VALUES, getString(getEcoreResourceLocator(), "_UI_InvalidValueFeatureHasTooManyValues_diagnostic", size, upperBound), values));
+  }
+
+  /**
+   * @see #INVALID_LOCATION
+   */
+  protected void reportInvalidLocation(EAnnotation eAnnotation, DiagnosticChain diagnostics, Map<Object, Object> context)
+  {
+    diagnostics.add(
+      createDiagnostic(
+        Diagnostic.WARNING,
+        INVALID_LOCATION,
+        getString(getEcoreResourceLocator(), "_UI_InvalidAnnotationLocation_diagnostic", annotationName, getValidLocationDescription()),
+        eAnnotation,
+        EcorePackage.Literals.EANNOTATION__SOURCE));
+  }
+
+  /**
+   * @see #INVALID_DUPLICATE
+   */
+  protected void reportDuplicate(
+    EAnnotation primaryEAnnotation,
+    EAnnotation secondaryEAnnotation,
+    EModelElement eModelElement,
+    DiagnosticChain diagnostics,
+    Map<Object, Object> context)
+  {
+    diagnostics.add(
+      createDiagnostic(
+        Diagnostic.WARNING,
+        INVALID_DUPLICATE,
+        getString(getEcoreResourceLocator(), "_UI_InvalidDuplicateAnnotation_diagnostic", annotationName, getValidLocationDescription()),
+        secondaryEAnnotation,
+        EcorePackage.Literals.EANNOTATION__SOURCE,
+        primaryEAnnotation));
+  }
+
+  /**
+   * @see #IGNORED_ENTRY
+   */
+  protected void reportIgnoredEntry(EAnnotation eAnnotation, EModelElement eModelElement, Map.Entry<String, String> entry, DiagnosticChain diagnostics, Map<Object, Object> context)
+  {
+    diagnostics.add(
+      createDiagnostic(
+        Diagnostic.WARNING,
+        IGNORED_ENTRY,
+        getString(getEcoreResourceLocator(), "_UI_InvalidAnnotationEntryKey_diagnostic", annotationName, entry.getKey()),
+        entry,
+        EcorePackage.Literals.ESTRING_TO_STRING_MAP_ENTRY__KEY));
+  }
+
+  /**
+   * @see #MISSING_ENTRY
+   */
+  protected void reportMissingEntry(
+    EAnnotation eAnnotation,
+    EModelElement eModelElement,
+    String key,
+    EStructuralFeature property,
+    DiagnosticChain diagnostics,
+    Map<Object, Object> context)
+  {
+    diagnostics.add(
+      createDiagnostic(
+        Diagnostic.WARNING,
+        MISSING_ENTRY,
+        getString(getEcoreResourceLocator(), "_UI_MissingAnnotationEntryKey_diagnostic", key),
+        eAnnotation,
+        EcorePackage.Literals.EANNOTATION__DETAILS));
+  }
+
+  /**
+   * @see #IGNORED_REFERENCES
+   */
+  protected void reportIgnoredReferences(
+    EAnnotation eAnnotation,
+    EModelElement eModelElement,
+    Collection<? extends EObject> ignoredReferences,
+    DiagnosticChain diagnostics,
+    Map<Object, Object> context)
+  {
+    List<Object> data = new ArrayList<Object>();
+    data.add(eAnnotation);
+    data.add(EcorePackage.Literals.EANNOTATION__REFERENCES);
+    data.addAll(ignoredReferences);
+    diagnostics.add(
+      createDiagnostic(Diagnostic.WARNING, IGNORED_REFERENCES, getString(getEcoreResourceLocator(), "_UI_IgnoredAnnotationReferences_diagnostic", annotationName), data.toArray()));
+  }
+
+  /**
+   * @see #INVALID_REFERENCE
+   */
+  protected void reportInvalidReference(EAnnotation eAnnotation, EModelElement eModelElement, EObject reference, DiagnosticChain diagnostics, Map<Object, Object> context)
+  {
+    diagnostics.add(
+      createDiagnostic(
+        Diagnostic.WARNING,
+        INVALID_REFERENCE,
+        getString(getEcoreResourceLocator(), "_UI_InvalidAnnotationReference_diagnostic", annotationName, EObjectValidator.getObjectLabel(reference, context)),
+        eAnnotation,
+        EcorePackage.Literals.EANNOTATION__REFERENCES,
+        reference));
+  }
+
+  /**
+   * @see #INVALID_REFERENCE
+   */
+  protected void reportIgnoredContents(
+    EAnnotation eAnnotation,
+    EModelElement eModelElement,
+    Collection<? extends EObject> ignoredContents,
+    DiagnosticChain diagnostics,
+    Map<Object, Object> context)
+  {
+    List<Object> data = new ArrayList<Object>();
+    data.add(eAnnotation);
+    data.add(EcorePackage.Literals.EANNOTATION__CONTENTS);
+    data.addAll(ignoredContents);
+    diagnostics.add(
+      createDiagnostic(Diagnostic.WARNING, INVALID_REFERENCE, getString(getEcoreResourceLocator(), "_UI_IgnoredAnnotationContents_diagnostic", annotationName), data.toArray()));
+  }
+
+  /**
+   * @see #INVALID_CONTENT
+   */
+  protected void reportInvalidContent(EAnnotation eAnnotation, EModelElement eModelElement, EObject content, DiagnosticChain diagnostics, Map<Object, Object> context)
+  {
+    diagnostics.add(
+      createDiagnostic(
+        Diagnostic.WARNING,
+        INVALID_CONTENT,
+        getString(getEcoreResourceLocator(), "_UI_InvalidAnnotationContent_diagnostic", annotationName, EObjectValidator.getObjectLabel(content, context)),
+        eAnnotation,
+        EcorePackage.Literals.EANNOTATION__CONTENTS,
+        content));
+  }
+
+  /**
+   * @see #IGNORED_ANNOTATIONS
+   */
+  protected void reportIgnoredAnnotations(
+    EAnnotation eAnnotation,
+    EModelElement eModelElement,
+    Collection<? extends EAnnotation> ignoredAnnotations,
+    DiagnosticChain diagnostics,
+    Map<Object, Object> context)
+  {
+    List<Object> data = new ArrayList<Object>();
+    data.add(eAnnotation);
+    data.add(EcorePackage.Literals.EMODEL_ELEMENT__EANNOTATIONS);
+    data.addAll(ignoredAnnotations);
+    diagnostics.add(
+      createDiagnostic(
+        Diagnostic.WARNING,
+        IGNORED_ANNOTATIONS,
+        getString(getEcoreResourceLocator(), "_UI_IgnoredAnnotationAnnotations_diagnostic", annotationName),
+        data.toArray()));
+  }
+
+  /**
+   * @see #INVALID_ANNOTATION
+   */
+  protected void reportInvalidAnnotation(
+    EAnnotation eAnnotation,
+    EModelElement eModelElement,
+    EAnnotation nestedEAnnotation,
+    DiagnosticChain diagnostics,
+    Map<Object, Object> context)
+  {
+    diagnostics.add(
+      createDiagnostic(
+        Diagnostic.WARNING,
+        INVALID_ANNOTATION,
+        getString(getEcoreResourceLocator(), "_UI_InvalidAnnotationAnnotation_diagnostic", annotationName, EObjectValidator.getObjectLabel(nestedEAnnotation, context)),
+        eAnnotation,
+        EcorePackage.Literals.EANNOTATION__CONTENTS,
+        nestedEAnnotation));
+  }
+
+  /**
+   * Returns a description of the valid locations supported for annotations of this annotation validator.
+   * <p>
+   * A annotation validator implementation must provide the key <code>"_UI_Valid" + {@link #annotationName annotationName} + "AnnotationLocation_substitution"</code> in its {@link #getResourceLocator() resource locator}
+   * with a very short description of the valid locations of annotations.
+   * </p>
+   * @return a description of the valid locations supported for annotations of this annotation validator.
+   * @see #reportInvalidLocation(EAnnotation, DiagnosticChain, Map)
+   */
+  protected String getValidLocationDescription()
+  {
+    return getString(getResourceLocator(), "_UI_Valid" + annotationName + "AnnotationLocation_substitution");
+  }
+
+  /**
+   * Creates the placeholder diagnostic used by {@link #validateFeatureDetail(EAnnotation, EModelElement, Map.Entry, EStructuralFeature, DiagnosticChain, Map) validateFeatureDetail}.
+   * Diagnostics about problems with the value of a {@link EAnnotation#getDetails() detail entry} will be nested as {@link Diagnostic#getChildren() children} of this annotation.
+   * @param eAnnotation the annotation.
+   * @param eModelElement the model element of that annotation.
+   * @param entry the entry.
+   * @param feature the feature.
+   * @return Creates a placeholder diagnostic.
+   */
+  protected BasicDiagnostic createValueDiagnostic(EAnnotation eAnnotation, EModelElement eModelElement, Map.Entry<String, String> entry, EStructuralFeature feature)
+  {
+    return createDiagnostic(
+      Diagnostic.OK,
+      INVALID_DETAIL_VALUE,
+      getString(getEcoreResourceLocator(), "_UI_InvalidAnnotationEntryValue_diagnostic", annotationName, entry.getKey()),
+      entry,
+      EcorePackage.Literals.ESTRING_TO_STRING_MAP_ENTRY__VALUE,
+      feature);
+  }
+
+  /**
+   * Returns the resource locator for fetching messages supported directly by the base implementation.
+   * @return the resource locator for fetching messages supported directly by the base implementation.
+   */
+  protected ResourceLocator getEcoreResourceLocator()
+  {
+    return EcorePlugin.INSTANCE;
+  }
+
+  /**
+   * Creates a diagnostic using the given parameters and the {@link #annotationSource}.
+   * @param severity
+   * @param code
+   * @param message
+   * @param data
+   * @return a diagnostic.
+   */
+  protected BasicDiagnostic createDiagnostic(int severity, int code, String message, Object... data)
+  {
+    return new BasicDiagnostic(severity, diagnosticSource, code, message, data);
+  }
+
+  /**
+   * Fetches a translated string from the resource locator using the message key and the give substitutions, if any.
+   * @param resourceLocator
+   * @param key
+   * @param substitutions
+   * @return the translated string for the message key.
+   */
+  protected String getString(ResourceLocator resourceLocator, String key, Object... substitutions)
+  {
+    return substitutions == null ? resourceLocator.getString(key) : resourceLocator.getString(key, substitutions);
+  }
+
+  /**
+   * Returns the root validator of the context.
+   * @param context the context.
+   * @return the root validator
+   */
+  protected EValidator getRootEValidator(Map<Object, Object> context)
+  {
+    if (context != null)
+    {
+      EValidator result = (EValidator)context.get(EValidator.class);
+      if (result != null)
+      {
+        return result;
+      }
+    }
+
+    return Diagnostician.INSTANCE;
+  }
+
+  /**
+   * An assistant that is useful for inducing a user interface that represents the annotation information in a more structured way
+   * using {@link #getPropertyClasses(EModelElement) modeled objects} that are created by {@link #createInstance(EClass, EAnnotation)}.
+   * This implementation delegates to the {@link BasicEAnnotationValidator annotation validator} which in turn provides an {@link BasicEAnnotationValidator#getAssistant() accessor} for its to corresponding assistant.
+   * This class generally does not need to be specialized nor instantiated because every annotation validator provides an assistant.
+   * This class therefore is abstract though none of its methods are abstract.
+   */
+  public static abstract class Assistant
+  {
+    /**
+     * The annotation validator to which this assistant delegates.
+     */
+    protected final BasicEAnnotationValidator eAnnotationValidator;
+
+    /**
+     * Creates an instance that delegates to the give annotation validator.
+     */
+    public Assistant(BasicEAnnotationValidator eAnnotationValidator)
+    {
+      this.eAnnotationValidator = eAnnotationValidator;
+    }
+
+    /**
+     * Returns whether this annotation with this annotation validator's {@link EAnnotation#getSource() annotation source} is valid at its {@link EAnnotation#getEModelElement() current location}.
+     * <p>
+     * The implementation delegates to {@link BasicEAnnotationValidator#isValidLocation(EAnnotation)}.
+     * An induced user interface can use this to determine if it can/should use this assistant's information for representing modeled annotation information.
+     * </p>
+     * @param eAnnotation the annotation in question.
+     * @return whether this annotation with this annotation validator's annotation source is valid at its current location.
+     */
+    public boolean isValidLocation(EAnnotation eAnnotation)
+    {
+      return eAnnotationValidator.isValidLocation(eAnnotation);
+    }
+
+    /**
+     * Returns a map from key to {@link EStructuralFeature feature}.
+     * These represents the keys that are considered valid and can be processed by this annotation validator.
+     * <p>
+     * The implementation delegates to {@link BasicEAnnotationValidator#getProperties(EModelElement)}.
+     * An induced user interface can use this method to determine which properties to display.
+     * </p>
+     * @param eModelElement the model element that is being annotated.
+     * @return a map from key to feature.
+     * @see #getApplicableProperties(EObject, EAnnotation)
+     */
+    public Map<String, EStructuralFeature> getProperties(EModelElement eModelElement)
+    {
+      return eAnnotationValidator.getProperties(eModelElement);
+    }
+
+    /**
+     * Returns the model classes used to represent annotations for the given model element.
+     * <p>
+     * The implementation delegates to {@link BasicEAnnotationValidator#getPropertyClasses(EModelElement)}.
+     * An induced user interface can use this method to determine which instances to create for display purposes.
+     * </p>
+     * @param eModelElement the model element in question.
+     * @return the model classes used to represent annotations for the given model element.
+     */
+    public List<EClass> getPropertyClasses(EModelElement eModelElement)
+    {
+      return eAnnotationValidator.getPropertyClasses(eModelElement);
+    }
+
+    /**
+     * Creates an initialized instance of the modeled representation for the given annotation.
+     * <p>
+     * The implementation delegates to {@link BasicEAnnotationValidator#createInstance(EClass, EAnnotation)}.
+     * An induced user interface can use this method to create instances for display purposes.
+     * </p>
+     * @param eClass the class to be instantiated.
+     * @param eAnnotation the annotation with the information that needs to be represented.
+     * @return creates an initialized instance of the modeled representation for the given annotation.
+     */
+    public EObject createInstance(EClass eClass, EAnnotation eAnnotation)
+    {
+      return eAnnotationValidator.createInstance(eClass, eAnnotation);
+    }
+
+    public String convertPropertyValueToLiteral(EObject eObject, EStructuralFeature eStructuralFeature, Object value)
+    {
+      return eAnnotationValidator.convertPropertyValueToLiteral(eObject, eStructuralFeature, value);
+    }
+
+    /**
+     * Returns the {@link #getProperties(EModelElement) subset of properties} that are applicable for the current state of the modeled annotation instance.
+     * <p>
+     * This subset includes only those properties of the annotation's {@link EAnnotation#getEModelElement() containing} model element
+     * for which {@link BasicEAnnotationValidator#isApplicable(EObject, EStructuralFeature)} returns <code>true</code>.
+     * An induced user interface should avoid displaying properties that are not applicable for the current state of the modeled annotation instance.
+     * </p>
+     * @param eObject the modeled instance in question.
+     * @param eAnnotation the corresponding annotation of that modeled instance.
+     * @return the subset of properties that are applicable for the current state of the modeled annotation instance.
+     */
+    public Map<String, EStructuralFeature> getApplicableProperties(EObject eObject, EAnnotation eAnnotation)
+    {
+      EModelElement eModelElement = eAnnotation.getEModelElement();
+      Map<String, EStructuralFeature> properties = getProperties(eModelElement);
+      Map<String, EStructuralFeature> result = new LinkedHashMap<String, EStructuralFeature>();
+      for (Map.Entry<String, EStructuralFeature> entry : properties.entrySet())
+      {
+        EStructuralFeature eStructuralFeature = entry.getValue();
+        if (eAnnotationValidator.isApplicable(eObject, eStructuralFeature))
+        {
+          result.put(entry.getKey(), eStructuralFeature);
+        }
+      }
+      return Collections.unmodifiableMap(result);
+    }
+
+    /**
+     * Returns whether {@link EAnnotation#getReferences() references} are meaningful for this annotation.
+     * <p>
+     * The implementation delegates to {@link BasicEAnnotationValidator#isReferencesSupported(EAnnotation, EModelElement)},
+     * passing in the {@link EAnnotation#getEModelElement() containing} model element.
+     * An induced user interface should avoid providing the ability to specify references when this returns <code>false</code>.
+     * </p>
+     * @param eAnnotation the annotation in question.
+     * @return whether references are meaningful for this annotation.
+     */
+    public boolean isReferencesSupported(EAnnotation eAnnotation)
+    {
+      return eAnnotationValidator.isReferencesSupported(eAnnotation, eAnnotation.getEModelElement());
+    }
+
+    /**
+     * Returns the filtered collection of references that are valid for this annotation.
+     * <p>
+     * The implementation delegates to {@link BasicEAnnotationValidator#getValidReferences(EAnnotation, EModelElement, Collection)}, passing in the {@link EAnnotation#getEModelElement() containing model element}.
+     * An induced user interface should provide the ability to specify only the references returned by this method.
+     * The references argument may contain all reachable objects, some subset there of, or none at all;
+     * an implementation may choose to filter from this collection or to provide its own result, including objects not in this collection.
+     * </p>
+     * @param eAnnotation the annotation in question.
+     * @param references all reachable objects, some subset there of, or none at all.
+     * @return the objects that are valid as references for this annotation.
+     */
+    public Collection<?> getValidReferences(EAnnotation eAnnotation, Collection<?> references)
+    {
+      return eAnnotationValidator.getValidReferences(eAnnotation, eAnnotation.getEModelElement(), references);
+    }
+
+    /**
+     * Returns whether {@link EAnnotation#getContents() contents} are meaningful for this annotation.
+     * <p>
+     * The implementation delegates to {@link BasicEAnnotationValidator#isContentsSupported(EAnnotation, EModelElement)},
+     * passing in the {@link EAnnotation#getEModelElement() containing} model element and an empty list.
+     * An induced user interface should avoid providing the ability to specify contents when this returns <code>false</code>.
+     * </p>
+     * @param eAnnotation the annotation in question.
+     * @return whether contents are meaningful for this annotation.
+     */
+    public boolean isContentsSupported(EAnnotation eAnnotation)
+    {
+      return eAnnotationValidator.isContentsSupported(eAnnotation, eAnnotation.getEModelElement());
+    }
+
+    /**
+     * Returns the filtered collection of contents that are valid for this annotation.
+     * <p>
+     * The implementation delegates to {@link BasicEAnnotationValidator#getValidContents(EAnnotation, EModelElement, Collection)}
+     * passing in the {@link EAnnotation#getEModelElement() containing} model element.
+     * An induced user interface should provide the ability to specify only the contents returned by this method.
+     * </p>
+     * @param eAnnotation the annotation in question.
+     * @param contents nothing at all, or the {@link EAnnotation#getContents() potential contents} of the annotation.
+     * @return the objects that are valid as contents for this annotation.
+     */
+    public Collection<? extends EObject> getValidContents(EAnnotation eAnnotation, Collection<? extends EObject> contents)
+    {
+      return eAnnotationValidator.getValidContents(eAnnotation, eAnnotation.getEModelElement(), contents);
+    }
+
+    /**
+     * Returns whether {@link EAnnotation#getEAnnotations() nested annotations} are meaningful for this annotation.
+     * <p>
+     * The implementation delegates to {@link BasicEAnnotationValidator#isAnnotationsSupported(EAnnotation, EModelElement)}, passing in the {@link EAnnotation#getEModelElement() containing model element}.
+     * An induced user interface should avoid providing the ability to specify nested annotations when this returns <code>false</code>.
+     * </p>
+     * @param eAnnotation the annotation in question.
+     * @return whether annotations are meaningful for this annotation.
+     */
+    public boolean isAnnotationsSupported(EAnnotation eAnnotation)
+    {
+      return eAnnotationValidator.isAnnotationsSupported(eAnnotation, eAnnotation.getEModelElement());
+    }
+
+    /**
+     * Returns the filtered collection of nested annotations that are valid for this annotation.
+     * <p>
+     * The implementation delegates to {@link BasicEAnnotationValidator#getValidAnnotations(EAnnotation, EModelElement, Collection)}
+     * passing in the {@link EAnnotation#getEModelElement() containing} model element.
+     * An induced user interface should provide the ability to specify only the nested annotations returned by this method.
+     * </p>
+     * @param eAnnotation the annotation in question.
+     * @param annotations nothing at all, or the {@link EModelElement#getEAnnotations() current or potential nested annotations} of the annotation.
+     * @return the annotations that are valid as nested annotations for this annotation.
+     */
+    public Collection<? extends EAnnotation> getValidAnnotations(EAnnotation eAnnotation, Collection<? extends EAnnotation> annotations)
+    {
+      return eAnnotationValidator.getValidAnnotations(eAnnotation, eAnnotation.getEModelElement(), annotations);
+    }
+  }
+}
diff --git a/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/util/BasicExtendedMetaData.java b/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/util/BasicExtendedMetaData.java
index 4d820bb..d4f68eb 100644
--- a/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/util/BasicExtendedMetaData.java
+++ b/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/util/BasicExtendedMetaData.java
@@ -220,7 +220,8 @@
 
   public String getNamespace(EClassifier eClassifier)
   {
-    return getNamespace(eClassifier.getEPackage());
+    EPackage ePackage = eClassifier.getEPackage();
+    return ePackage == null ? null : getNamespace(ePackage);
   }
 
   public String getNamespace(EStructuralFeature eStructuralFeature)
@@ -228,6 +229,24 @@
     return getExtendedMetaData(eStructuralFeature).getNamespace();
   }
 
+  /**
+   * @since 2.14
+   */
+  protected String getPackageNamespace(EStructuralFeature eStructuralFeature)
+  {
+    EClass eContainingClass = eStructuralFeature.getEContainingClass();
+    if (eContainingClass != null)
+    {
+      EPackage ePackage = eContainingClass.getEPackage();
+      if (ePackage != null)
+      {
+        return getNamespace(ePackage);
+      }
+    }
+    
+    return null;
+  }
+
   public String basicGetNamespace(EStructuralFeature eStructuralFeature)
   {
     EAnnotation eAnnotation = getAnnotation(eStructuralFeature, false);
@@ -240,7 +259,7 @@
       String result = eAnnotation.getDetails().get("namespace");
       if ("##targetNamespace".equals(result))
       {
-        return getNamespace(eStructuralFeature.getEContainingClass().getEPackage());
+        return getPackageNamespace(eStructuralFeature);
       }
       else
       {
@@ -251,7 +270,7 @@
 
   public void setNamespace(EStructuralFeature eStructuralFeature, String namespace)
   {
-    String packageNamespace = getNamespace(eStructuralFeature.getEContainingClass().getEPackage());
+    String packageNamespace = getPackageNamespace(eStructuralFeature);
     String convertedNamespace = namespace;
     if (namespace == null ? packageNamespace == null : namespace.equals(packageNamespace))
     {
@@ -532,25 +551,38 @@
     {
       EMap<String, String> details = eAnnotation.getDetails();
       String baseType = details.get("baseType");
-      if (baseType != null)
+      EClassifier type = getEClassifier(eDataType.getEPackage(), baseType);
+      if (type instanceof EDataType)
       {
-        int index = baseType.lastIndexOf("#");
-        EClassifier type = 
-          index == -1 ?
-            getType(eDataType.getEPackage(), baseType) :
-            index == 0 ?
-              getType((String)null, baseType.substring(1)) :
-              getType(baseType.substring(0, index), baseType.substring(index + 1));
-        if (type instanceof EDataType)
-        {
-          return (EDataType)type;
-        }
+        return (EDataType)type;
       }
     }
 
     return null;
   }
 
+  /**
+   * @since 2.14
+   */
+  protected EClassifier getEClassifier(EPackage ePackage, String type)
+  {
+    if (type == null)
+    {
+      return null;
+    }
+    else
+    {
+      int index = type.lastIndexOf("#");
+      EClassifier eClassifier = 
+        index == -1 ?
+          ePackage == null ? null : getType(ePackage, type) :
+          index == 0 ?
+            getType((String)null, type.substring(1)) :
+            getType(type.substring(0, index), type.substring(index + 1));
+      return eClassifier;
+    }
+  }
+
   public void setBaseType(EDataType eDataType, EDataType baseType)
   {
     if (baseType == null)
@@ -581,19 +613,10 @@
     {
       EMap<String, String> details = eAnnotation.getDetails();
       String itemType = details.get("itemType");
-      if (itemType != null)
+      EClassifier type = getEClassifier(eDataType.getEPackage(), itemType);
+      if (type instanceof EDataType)
       {
-        int index = itemType.lastIndexOf("#");
-        EClassifier type = 
-          index == -1 ?
-            getType(eDataType.getEPackage(), itemType) :
-            index == 0 ?
-              getType((String)null, itemType.substring(1)) :
-              getType(itemType.substring(0, index), itemType.substring(index + 1));
-        if (type instanceof EDataType)
-        {
-          return (EDataType)type;
-        }
+        return (EDataType)type;
       }
     }
 
@@ -632,16 +655,11 @@
       if (memberTypes != null)
       {
         List<EDataType> result = new ArrayList<EDataType>();
+        EPackage ePackage = eDataType.getEPackage();
         for (StringTokenizer stringTokenizer = new StringTokenizer(memberTypes); stringTokenizer.hasMoreTokens(); )
         {
           String member = stringTokenizer.nextToken();
-          int index = member.lastIndexOf("#");
-          EClassifier type = 
-            index == -1 ?
-              getType(eDataType.getEPackage(), member) :
-              index == 0 ?
-                getType((String)null, member.substring(1)) :
-                getType(member.substring(0, index), member.substring(index + 1));
+          EClassifier type = getEClassifier(ePackage, member);
           if (type instanceof EDataType)
           {
             result.add((EDataType)type);
@@ -821,6 +839,7 @@
         switch (getFeatureKind(eStructuralFeature))
         {
           case UNSPECIFIED_FEATURE:
+          case GROUP_FEATURE:
           case ELEMENT_FEATURE:
           {
             if (name.equals(getName(eStructuralFeature)))
@@ -1075,7 +1094,7 @@
           String wildcard = stringTokenizer.nextToken();
           if (wildcard.equals("##other"))
           {
-            result.add("!##" + getNamespace(eStructuralFeature.getEContainingClass().getEPackage()));
+            result.add("!##" + getPackageNamespace(eStructuralFeature));
           }
           else if (wildcard.equals("##local"))
           {
@@ -1083,7 +1102,7 @@
           }
           else if (wildcard.equals("##targetNamespace"))
           {
-            result.add(getNamespace(eStructuralFeature.getEContainingClass().getEPackage()));
+            result.add(getPackageNamespace(eStructuralFeature));
           }
           else
           {
@@ -1110,7 +1129,7 @@
     }
     else
     {
-      String namespace = getNamespace(eStructuralFeature.getEContainingClass().getEPackage());
+      String namespace = getPackageNamespace(eStructuralFeature);
       EAnnotation eAnnotation = getAnnotation(eStructuralFeature, true);
       eAnnotation.getDetails().put("wildcards", getEncodedWildcards(namespace, wildcards));
       eAnnotation.getDetails().put("name","");
@@ -1229,13 +1248,19 @@
       String qualifiedName = eAnnotation.getDetails().get("group");
       if (qualifiedName != null)
       {
-        int fragmentIndex = qualifiedName.lastIndexOf('#');
         EClass eContainingClass = eStructuralFeature.getEContainingClass();
+        if (eContainingClass == null)
+        {
+          return null;
+        }
+
+        int fragmentIndex = qualifiedName.lastIndexOf('#');
         String namespace;
         String name;
         if (fragmentIndex == -1)
         {
-          namespace = getNamespace(eContainingClass.getEPackage());
+          EPackage ePackage = eContainingClass.getEPackage();
+          namespace = ePackage == null ? null : getNamespace(ePackage);
           name = qualifiedName;
         }
         else if (fragmentIndex == 0)
@@ -1291,7 +1316,7 @@
     {
       EAnnotation eAnnotation = getAnnotation(eStructuralFeature, true);
       eAnnotation.getDetails().put
-        ("group", getQualifiedName(getNamespace(eStructuralFeature.getEContainingClass().getEPackage()), group));
+        ("group", getQualifiedName(getPackageNamespace(eStructuralFeature), group));
     }
     getExtendedMetaData(eStructuralFeature).setGroup(group);
   }
@@ -1312,11 +1337,18 @@
         int fragmentIndex = qualifiedName.lastIndexOf('#');
         if (fragmentIndex == -1)
         {
-          EPackage ePackage = eStructuralFeature.getEContainingClass().getEPackage();
-          EClass documentRoot = getDocumentRoot(ePackage);
-          if (documentRoot != null)
+          EClass eContainingClass = eStructuralFeature.getEContainingClass();
+          if (eContainingClass != null)
           {
-            return getLocalElement(documentRoot, getNamespace(ePackage), qualifiedName);
+            EPackage ePackage = eContainingClass.getEPackage();
+            if (ePackage != null)
+            {
+              EClass documentRoot = getDocumentRoot(ePackage);
+              if (documentRoot != null)
+              {
+                return getLocalElement(documentRoot, getNamespace(ePackage), qualifiedName);
+              }
+            }
           }
         }
         else if (fragmentIndex == 0)
@@ -1346,7 +1378,7 @@
     {
       EAnnotation eAnnotation = getAnnotation(eStructuralFeature, true);
       eAnnotation.getDetails().put
-        ("affiliation", getQualifiedName(getNamespace(eStructuralFeature.getEContainingClass().getEPackage()), affiliation));
+        ("affiliation", getQualifiedName(getPackageNamespace(eStructuralFeature), affiliation));
     }
     getExtendedMetaData(eStructuralFeature).setAffiliation(affiliation);
   }
@@ -1362,7 +1394,8 @@
     {
       case ATTRIBUTE_FEATURE:
       {
-        if (isDocumentRoot(eStructuralFeature.getEContainingClass()))
+        EClass eContainingClass = eStructuralFeature.getEContainingClass();
+        if (eContainingClass != null && isDocumentRoot(eContainingClass))
         {
           String namespace = getNamespace(eStructuralFeature);
           String name = getName(eStructuralFeature);
@@ -1386,7 +1419,8 @@
       }
       case ELEMENT_FEATURE:
       {
-        if (isDocumentRoot(eStructuralFeature.getEContainingClass()))
+        EClass eContainingClass = eStructuralFeature.getEContainingClass();
+        if (eContainingClass != null && isDocumentRoot(eContainingClass))
         {
           for (EStructuralFeature affiliation = eStructuralFeature; affiliation != null; affiliation = getAffiliation(affiliation))
           {
@@ -1628,6 +1662,18 @@
     return getExtendedMetaData(eDataType).getTotalDigitsFacet();
   }
 
+  private int parseInt(String literal)
+  {
+    try
+    {
+      return Integer.parseInt(literal);
+    }
+    catch (NumberFormatException exception)
+    {
+      return -1;
+    }
+  }
+
   protected int basicGetTotalDigitsFacet(EDataType eDataType)
   {
     EAnnotation eAnnotation = getAnnotation(eDataType, false);
@@ -1636,7 +1682,7 @@
       String totalDigitsLiteral = eAnnotation.getDetails().get("totalDigits");
       if (totalDigitsLiteral != null)
       {
-        return Integer.parseInt(totalDigitsLiteral);
+        return parseInt(totalDigitsLiteral);
       }
     }
     return -1;
@@ -1673,7 +1719,7 @@
       String fractionDigitsLiteral = eAnnotation.getDetails().get("fractionDigits");
       if (fractionDigitsLiteral != null)
       {
-        return Integer.parseInt(fractionDigitsLiteral);
+        return parseInt(fractionDigitsLiteral);
       }
     }
     return -1;
@@ -1710,7 +1756,7 @@
       String lengthLiteral = eAnnotation.getDetails().get("length");
       if (lengthLiteral != null)
       {
-        return Integer.parseInt(lengthLiteral);
+        return parseInt(lengthLiteral);
       }
     }
     return -1;
@@ -1747,7 +1793,7 @@
       String minLengthLiteral = eAnnotation.getDetails().get("minLength");
       if (minLengthLiteral != null)
       {
-        return Integer.parseInt(minLengthLiteral);
+        return parseInt(minLengthLiteral);
       }
     }
     return -1;
@@ -1784,7 +1830,7 @@
       String maxLengthLiteral = eAnnotation.getDetails().get("maxLength");
       if (maxLengthLiteral != null)
       {
-        return Integer.parseInt(maxLengthLiteral);
+        return parseInt(maxLengthLiteral);
       }
     }
     return -1;
diff --git a/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/util/EcoreAnnotationValidator.java b/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/util/EcoreAnnotationValidator.java
new file mode 100644
index 0000000..180dbf8
--- /dev/null
+++ b/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/util/EcoreAnnotationValidator.java
@@ -0,0 +1,299 @@
+/**
+ * Copyright (c) 2017 Eclipse contributors and others.
+ * All rights reserved.   This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.eclipse.emf.ecore.util;
+
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.emf.common.util.Diagnostic;
+import org.eclipse.emf.common.util.DiagnosticChain;
+import org.eclipse.emf.common.util.EList;
+import org.eclipse.emf.common.util.ResourceLocator;
+import org.eclipse.emf.ecore.EAnnotation;
+import org.eclipse.emf.ecore.EAttribute;
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EClassifier;
+import org.eclipse.emf.ecore.EDataType;
+import org.eclipse.emf.ecore.EModelElement;
+import org.eclipse.emf.ecore.EOperation;
+import org.eclipse.emf.ecore.EPackage;
+import org.eclipse.emf.ecore.EValidator;
+import org.eclipse.emf.ecore.EcoreFactory;
+import org.eclipse.emf.ecore.EcorePackage;
+
+
+/**
+ *  An annotation validator for {@link EcorePackage#eNS_URI Ecore} annotations.
+ *
+ * @since 2.14
+ */
+public final class EcoreAnnotationValidator extends BasicEAnnotationValidator
+{
+  public static final EcoreAnnotationValidator INSTANCE = new EcoreAnnotationValidator();
+
+  public static final String DIAGNOSTIC_SOURCE = "org.eclipse.emf.ecore.annotation";
+
+  public EcoreAnnotationValidator()
+  {
+    super(EcorePackage.eNS_URI, "Ecore", DIAGNOSTIC_SOURCE);
+
+    //    int xxx;
+    //    // This can be used to test an annotation validator that supports annotations on annotations.
+    //    EAnnotationValidator.Registry.INSTANCE.put("Testing", new BasicEAnnotationValidator("Testing", "Testing", "..testing")
+    //      {
+    //        @Override
+    //        protected ResourceLocator getResourceLocator()
+    //        {
+    //          return EcorePlugin.INSTANCE;
+    //        }
+    //
+    //        @Override
+    //        protected boolean isValidLocation(EAnnotation eAnnotation, EModelElement eModelElement)
+    //        {
+    //          return eModelElement instanceof EAnnotation;
+    //        }
+    //
+    //        @Override
+    //        protected boolean isDuplicateValid(EModelElement eModelElement, EAnnotation primaryEAnnotation, EAnnotation secondaryEAnnotation)
+    //        {
+    //          return true;
+    //        }
+    //
+    //        @Override
+    //        protected boolean isContentsSupported(EAnnotation eAnnotation, EModelElement eModelElement)
+    //        {
+    //          return true;
+    //        }
+    //
+    //        @Override
+    //        protected Collection<? extends EObject> getValidContents(EAnnotation eAnnotation, EModelElement eModelElement, Collection<? extends EObject> contents)
+    //        {
+    //          ArrayList<EObject> result = new ArrayList<EObject>(contents);
+    //          for (EObject eObject : contents)
+    //          {
+    //            if (!(eObject instanceof EClass))
+    //            {
+    //              result.remove(eObject);
+    //            }
+    //          }
+    //          result.add(EcoreFactory.eINSTANCE.createEClass());
+    //          return result;
+    //        }
+    //
+    //        @Override
+    //        protected boolean isReferencesSupported(EAnnotation eAnnotation, EModelElement eModelElement)
+    //        {
+    //          return true;
+    //        }
+    //
+    //        @Override
+    //        protected Collection<?> getValidReferences(EAnnotation eAnnotation, EModelElement eModelElement, Collection<?> references)
+    //        {
+    //          ArrayList<Object> result = new ArrayList<Object>(references);
+    //          for (Object object : references)
+    //          {
+    //            if (!(object instanceof EDataType))
+    //            {
+    //              result.remove(object);
+    //            }
+    //          }
+    //          return result;
+    //        }
+    //
+    //        @Override
+    //        protected List<EClass> getPropertyClasses(EModelElement eModelElement)
+    //        {
+    //          return Collections.emptyList();
+    //        }
+    //      });
+  }
+
+  @Override
+  protected ResourceLocator getResourceLocator()
+  {
+    return getEcoreResourceLocator();
+  }
+
+  @Override
+  protected boolean isValidLocation(EAnnotation eAnnotation, EModelElement eModelElement)
+  {
+    return !getProperties(eModelElement).isEmpty();
+  }
+
+  @Override
+  protected List<EClass> getPropertyClasses(EModelElement eModelElement)
+  {
+    final List<EClass> result = new ArrayList<EClass>(1);
+    new PropertySwitch()
+      {
+        @Override
+        protected void addFeatures(EClass eClass)
+        {
+          result.add(eClass);
+        }
+      }.doSwitch(eModelElement);
+    return result.size() == 0 ? Collections.<EClass> emptyList() : Collections.singletonList(result.get(0));
+  }
+
+  private static abstract class PropertySwitch extends EcoreSwitch<Void>
+  {
+    private static final EClass ANNOTATION_PACKAGE_CLASS;
+
+    private static final EClass ANNOTATION_CLASSIFIER_CLASS;
+
+    private static final EClass ANNOTATION_OPERATION_CLASS;
+
+    static
+    {
+      EPackage ePackage = EcoreFactory.eINSTANCE.createEPackage();
+      ePackage.setName("annotation");
+      ePackage.setNsPrefix("annotation");
+      ePackage.setNsURI("annotation");
+      EList<EClassifier> eClassifiers = ePackage.getEClassifiers();
+
+      final EDataType javaIdentifier = EcoreFactory.eINSTANCE.createEDataType();
+      javaIdentifier.setName("JavaIdentifier");
+      javaIdentifier.setInstanceClass(String.class);
+      ePackage.getEClassifiers().add(javaIdentifier);
+
+      final EDataType uriDataType = EcoreFactory.eINSTANCE.createEDataType();
+      uriDataType.setName("WellFormedURI");
+      uriDataType.setInstanceClass(String.class);
+      ePackage.getEClassifiers().add(uriDataType);
+
+      ANNOTATION_PACKAGE_CLASS = EcoreFactory.eINSTANCE.createEClass();
+      ANNOTATION_PACKAGE_CLASS.setName("Package");
+      eClassifiers.add(ANNOTATION_PACKAGE_CLASS);
+
+      EAttribute schemaLocationAttribute = EcoreFactory.eINSTANCE.createEAttribute();
+      schemaLocationAttribute.setName("schemaLocation");
+      schemaLocationAttribute.setEType(uriDataType);
+      ANNOTATION_PACKAGE_CLASS.getEStructuralFeatures().add(schemaLocationAttribute);
+
+      EAttribute settingDelegatesAttribute = EcoreFactory.eINSTANCE.createEAttribute();
+      settingDelegatesAttribute.setName("settingDelegates");
+      settingDelegatesAttribute.setUpperBound(-1);
+      settingDelegatesAttribute.setEType(uriDataType);
+      ANNOTATION_PACKAGE_CLASS.getEStructuralFeatures().add(settingDelegatesAttribute);
+
+      EAttribute validationDelegatesAttribute = EcoreFactory.eINSTANCE.createEAttribute();
+      validationDelegatesAttribute.setName("validationDelegates");
+      validationDelegatesAttribute.setUpperBound(-1);
+      validationDelegatesAttribute.setEType(uriDataType);
+      ANNOTATION_PACKAGE_CLASS.getEStructuralFeatures().add(validationDelegatesAttribute);
+
+      EAttribute invocationDelegatesAttribute = EcoreFactory.eINSTANCE.createEAttribute();
+      invocationDelegatesAttribute.setName("invocationDelegates");
+      invocationDelegatesAttribute.setUpperBound(-1);
+      invocationDelegatesAttribute.setEType(uriDataType);
+      ANNOTATION_PACKAGE_CLASS.getEStructuralFeatures().add(invocationDelegatesAttribute);
+
+      EAttribute conversionDelegatesAttribute = EcoreFactory.eINSTANCE.createEAttribute();
+      conversionDelegatesAttribute.setName("conversionDelegates");
+      conversionDelegatesAttribute.setUpperBound(-1);
+      conversionDelegatesAttribute.setEType(uriDataType);
+      ANNOTATION_PACKAGE_CLASS.getEStructuralFeatures().add(conversionDelegatesAttribute);
+
+      ANNOTATION_CLASSIFIER_CLASS = EcoreFactory.eINSTANCE.createEClass();
+      ANNOTATION_CLASSIFIER_CLASS.setName("Classifier");
+      eClassifiers.add(ANNOTATION_CLASSIFIER_CLASS);
+
+      EAttribute constraintsAttribute = EcoreFactory.eINSTANCE.createEAttribute();
+      constraintsAttribute.setName("constraints");
+      constraintsAttribute.setEType(javaIdentifier);
+      constraintsAttribute.setUpperBound(-1);
+      ANNOTATION_CLASSIFIER_CLASS.getEStructuralFeatures().add(constraintsAttribute);
+
+      ANNOTATION_OPERATION_CLASS = EcoreFactory.eINSTANCE.createEClass();
+      ANNOTATION_OPERATION_CLASS.setName("Operation");
+      eClassifiers.add(ANNOTATION_OPERATION_CLASS);
+
+      EAttribute invariantAttribute = EcoreFactory.eINSTANCE.createEAttribute();
+      invariantAttribute.setName("invariant");
+      invariantAttribute.setEType(EcorePackage.Literals.EBOOLEAN);
+      ANNOTATION_OPERATION_CLASS.getEStructuralFeatures().add(invariantAttribute);
+
+      EValidator.Registry.INSTANCE.put(ePackage, new EObjectValidator()
+        {
+          @Override
+          public boolean validate(EDataType eDataType, Object value, DiagnosticChain diagnostics, Map<Object, Object> context)
+          {
+            boolean result = super.validate(eDataType, value, diagnostics, context);
+            if (result)
+            {
+              if (eDataType == javaIdentifier)
+              {
+                if (javaIdentifier != null)
+                {
+                  result = EcoreValidator.isWellFormedJavaIdentifier((String)value);
+                  if (!result && diagnostics != null)
+                  {
+                    diagnostics.add(
+                      createDiagnostic(
+                        Diagnostic.ERROR,
+                        DIAGNOSTIC_SOURCE,
+                        0,
+                        "_UI_NameNotWellFormedJavaIdentifier_diagnostic",
+                        new Object []{ value },
+                        new Object []{ value },
+                        context));
+                  }
+                }
+              }
+              else if (eDataType == uriDataType)
+              {
+                if (value != null)
+                {
+                  result = EcoreValidator.isWellFormedURI((String)value);
+                  if (!result && diagnostics != null)
+                  {
+                    diagnostics.add(
+                      createDiagnostic(
+                        Diagnostic.ERROR,
+                        DIAGNOSTIC_SOURCE,
+                        0,
+                        "_UI_EAnnotationSourceURINotWellFormed_diagnostic",
+                        new Object []{ value },
+                        new Object []{ value },
+                        context));
+                  }
+                }
+              }
+            }
+            return result;
+          }
+        });
+    }
+
+    protected abstract void addFeatures(EClass eClass);
+
+    @Override
+    public Void caseEClassifier(EClassifier eClassifier)
+    {
+      addFeatures(ANNOTATION_CLASSIFIER_CLASS);
+      return null;
+    }
+
+    @Override
+    public Void caseEOperation(EOperation eOperation)
+    {
+      addFeatures(ANNOTATION_OPERATION_CLASS);
+      return null;
+    }
+
+    @Override
+    public Void caseEPackage(EPackage object)
+    {
+      addFeatures(ANNOTATION_PACKAGE_CLASS);
+      return null;
+    }
+  }
+}
diff --git a/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/util/EcoreUtil.java b/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/util/EcoreUtil.java
index c01721e..449d9e4 100644
--- a/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/util/EcoreUtil.java
+++ b/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/util/EcoreUtil.java
@@ -3793,6 +3793,13 @@
 
   protected static final String GEN_MODEL_PACKAGE_NS_URI = "http://www.eclipse.org/emf/2002/GenModel";
 
+  /**
+   * The {@link EAnnotation#getSource() source} URI for GenModel annotations.
+   *
+   * @since 2.14
+   */
+  public static final String GEN_MODEL_ANNOTATION_URI = GEN_MODEL_PACKAGE_NS_URI;
+
   public static String getDocumentation(EModelElement eModelElement)
   {
     EAnnotation eAnnotation = eModelElement.getEAnnotation(GEN_MODEL_PACKAGE_NS_URI);
diff --git a/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/util/EcoreValidator.java b/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/util/EcoreValidator.java
index ef309eb..9eae7bf 100644
--- a/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/util/EcoreValidator.java
+++ b/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/util/EcoreValidator.java
@@ -37,8 +37,6 @@
 import org.eclipse.emf.common.util.UniqueEList;
 
 import org.eclipse.emf.ecore.*;
-
-import org.eclipse.emf.ecore.EPackage;
 import org.eclipse.emf.ecore.plugin.EcorePlugin;
 
 import org.eclipse.emf.ecore.resource.Resource;
@@ -601,11 +599,33 @@
     if (result || diagnostics != null) result &= validate_UniqueID(eAnnotation, diagnostics, context);
     if (result || diagnostics != null) result &= validate_EveryKeyUnique(eAnnotation, diagnostics, context);
     if (result || diagnostics != null) result &= validate_EveryMapEntryUnique(eAnnotation, diagnostics, context);
+    if (result || diagnostics != null) result &= validateEAnnotation_WellFormed(eAnnotation, diagnostics, context);
     if (result || diagnostics != null) result &= validateEAnnotation_WellFormedSourceURI(eAnnotation, diagnostics, context);
     return result;
   }
 
   /**
+   * Validates the WellFormed constraint of '<em>EAnnotation</em>'.
+   * <!-- begin-user-doc -->
+   * @since 2.14
+   * @see EAnnotationValidator#validate(EAnnotation, DiagnosticChain, Map)
+   * <!-- end-user-doc -->
+   * @generated NOT
+   */
+  public boolean validateEAnnotation_WellFormed(EAnnotation eAnnotation, DiagnosticChain diagnostics, Map<Object, Object> context)
+  {
+    EAnnotationValidator eAnnotationValidator = EAnnotationValidator.Registry.INSTANCE.getEAnnotationValidator(eAnnotation.getSource());
+    if (eAnnotationValidator != null)
+    {
+      return eAnnotationValidator.validate(eAnnotation, diagnostics, context);
+    }
+    else
+    {
+      return true;
+    }
+  }
+
+  /**
    * Validates the WellFormedSourceURI constraint of '<em>EAnnotation</em>'.
    * <!-- begin-user-doc -->
    * The source URI must either be either <code>null</code> or {@link #isWellFormedURI(String) well formed}.
@@ -654,6 +674,40 @@
   }
 
   /**
+   * A well formed Java identifier must start with a {@link Character#isJavaIdentifierStart(int) Java identifier start} character
+   * followed by zero or more {@link Character#isJavaIdentifierPart(int) Java identifier part} characters.
+   * @param name the name in question.
+   * @return whether the name is a well formed Java identifier.
+   * @since 2.14
+   */
+  public static boolean isWellFormedJavaIdentifier(String name)
+  {
+    boolean result = false;
+    if (name != null)
+    {
+      int length = name.length();
+      if (length > 0)
+      {
+        int codePoint = name.codePointAt(0);
+        if (Character.isJavaIdentifierStart(codePoint) && codePoint != '$')
+        {
+          result = true;
+          for (int i = Character.offsetByCodePoints(name, 0, 1); i < length; i = Character.offsetByCodePoints(name, i, 1))
+          {
+            codePoint = name.codePointAt(i);
+            if (codePoint == '$' || !Character.isJavaIdentifierPart(codePoint))
+            {
+              result = false;
+              break;
+            }
+          }
+        }
+      }
+    }
+    return result;
+  }
+
+  /**
    * <!-- begin-user-doc -->
    * <!-- end-user-doc -->
    * @generated
@@ -1932,30 +1986,8 @@
       return true;
     }
 
-    boolean result = false;
     String name = eNamedElement.getName();
-    if (name != null)
-    {
-      int length = name.length();
-      if (length > 0)
-      {
-        int codePoint = name.codePointAt(0);
-        if (Character.isJavaIdentifierStart(codePoint) && codePoint != '$')
-        {
-          result = true;
-          for (int i = Character.offsetByCodePoints(name, 0, 1); i < length; i = Character.offsetByCodePoints(name, i, 1))
-          {
-            codePoint = name.codePointAt(i);
-            if (codePoint == '$' || !Character.isJavaIdentifierPart(codePoint))
-            {
-              result = false;
-              break;
-            }
-          }
-        }
-      }
-    }
-
+    boolean result = isWellFormedJavaIdentifier(name);
     if (!result && diagnostics != null)
     {
       diagnostics.add
diff --git a/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/util/ExtendedMetaDataAnnotationValidator.java b/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/util/ExtendedMetaDataAnnotationValidator.java
new file mode 100644
index 0000000..d730ae5
--- /dev/null
+++ b/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/util/ExtendedMetaDataAnnotationValidator.java
@@ -0,0 +1,1542 @@
+/**
+ * Copyright (c) 2017 Eclipse contributors and others.
+ * All rights reserved.   This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.eclipse.emf.ecore.util;
+
+
+import java.lang.reflect.Method;
+import java.math.BigDecimal;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.WeakHashMap;
+import java.util.Map.Entry;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.eclipse.emf.common.util.BasicDiagnostic;
+import org.eclipse.emf.common.util.Diagnostic;
+import org.eclipse.emf.common.util.DiagnosticChain;
+import org.eclipse.emf.common.util.ECollections;
+import org.eclipse.emf.common.util.EList;
+import org.eclipse.emf.common.util.EMap;
+import org.eclipse.emf.common.util.Enumerator;
+import org.eclipse.emf.common.util.ResourceLocator;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.EAnnotation;
+import org.eclipse.emf.ecore.EAttribute;
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EClassifier;
+import org.eclipse.emf.ecore.EDataType;
+import org.eclipse.emf.ecore.EEnum;
+import org.eclipse.emf.ecore.EModelElement;
+import org.eclipse.emf.ecore.ENamedElement;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EPackage;
+import org.eclipse.emf.ecore.EReference;
+import org.eclipse.emf.ecore.EStructuralFeature;
+import org.eclipse.emf.ecore.ETypedElement;
+import org.eclipse.emf.ecore.EValidator;
+import org.eclipse.emf.ecore.EcoreFactory;
+import org.eclipse.emf.ecore.EcorePackage;
+import org.eclipse.emf.ecore.impl.EFactoryImpl;
+import org.eclipse.emf.ecore.impl.EPackageImpl;
+import org.eclipse.emf.ecore.impl.EPackageRegistryImpl;
+import org.eclipse.emf.ecore.impl.MinimalEObjectImpl;
+import org.eclipse.emf.ecore.plugin.EcorePlugin;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.emf.ecore.resource.ResourceSet;
+import org.eclipse.emf.ecore.xml.type.XMLTypePackage;
+import org.eclipse.emf.ecore.xml.type.util.XMLTypeUtil;
+
+
+/**
+ *  An annotation validator for {@link ExtendedMetaData#ANNOTATION_URI ExtendedMetadata} annotations.
+ *
+ * @since 2.14
+ */
+public final class ExtendedMetaDataAnnotationValidator extends BasicEAnnotationValidator
+{
+  public static final ExtendedMetaDataAnnotationValidator INSTANCE = new ExtendedMetaDataAnnotationValidator();
+
+  public static final String DIAGNOSTIC_SOURCE = "org.eclipse.emf.ecore.annotation.extended.meta.data";
+
+  /**
+   * @see SpecializedExtendedMetaData#reportBadValue(Object, DiagnosticChain, int, String, Object...)
+   */
+  public static final int INVALID_VALUE_LITERAL = BasicEAnnotationValidator.INVALID_VALUE_LITERAL;
+
+  /**
+   * @see SpecializedExtendedMetaData#reportIgnoredEntry(Entry, DiagnosticChain, String, Object...)
+   */
+  public static final int IGNORED_ENTRY = BasicEAnnotationValidator.IGNORED_ENTRY;
+
+  private static String INSTANCE_VALUE = "extended_meta_data_instance_value";
+
+  public ExtendedMetaDataAnnotationValidator()
+  {
+    super(ExtendedMetaData.ANNOTATION_URI, "ExtendedMetaData", DIAGNOSTIC_SOURCE);
+  }
+
+  @Override
+  protected ResourceLocator getResourceLocator()
+  {
+    return getEcoreResourceLocator();
+  }
+
+  @Override
+  protected EObject initialize(EObject eObject, EAnnotation eAnnotation)
+  {
+    ModelObject result = (ModelObject)eObject;
+    result.setElement((ENamedElement)eAnnotation.getEModelElement());
+    return result;
+  }
+
+  @Override
+  protected boolean isApplicable(EObject eObject, EStructuralFeature eStructuralFeature)
+  {
+    return ((ModelObject)eObject).isApplicable(eStructuralFeature);
+  }
+
+  @Override
+  protected boolean isValidLocation(EAnnotation eAnnotation, EModelElement eModelElement)
+  {
+    return getPropertyClass(eModelElement) != null;
+  }
+
+  @Override
+  protected List<EClass> getPropertyClasses(EModelElement eModelElement)
+  {
+    EClass propertyClass = getPropertyClass(eModelElement);
+    return propertyClass == null ? Collections.<EClass> emptyList() : Collections.<EClass> singletonList(propertyClass);
+  }
+
+  private EClass getPropertyClass(EModelElement eModelElement)
+  {
+    final AtomicReference<EClass> result = new AtomicReference<EClass>();
+    new PropertySwitch()
+      {
+        @Override
+        protected void addFeatures(EClass eClass)
+        {
+          result.set(eClass);
+        }
+      }.doSwitch(eModelElement);
+    return result.get();
+  }
+
+  @Override
+  protected boolean validateDetails(EAnnotation eAnnotation, EModelElement eModelElement, DiagnosticChain diagnostics, Map<Object, Object> context)
+  {
+    if (context == null)
+    {
+      context = new HashMap<Object, Object>();
+    }
+
+    EClass propertyClass = getPropertyClass(eModelElement);
+    ModelObject modelObject = (ModelObject)createInstance(propertyClass, eAnnotation);
+    try
+    {
+      context.put(INSTANCE_VALUE, modelObject);
+      return super.validateDetails(eAnnotation, eModelElement, diagnostics, context);
+    }
+    finally
+    {
+      context.remove(INSTANCE_VALUE);
+    }
+  }
+
+  @Override
+  protected boolean validateFeatureDetail(
+    EAnnotation eAnnotation,
+    EModelElement eModelElement,
+    Entry<String, String> entry,
+    EStructuralFeature feature,
+    DiagnosticChain diagnostics,
+    Map<Object, Object> context)
+  {
+    boolean result = getModelObject(context).validateEntry(this, entry, diagnostics, context);
+    if (result)
+    {
+      result = super.validateFeatureDetail(eAnnotation, eModelElement, entry, feature, diagnostics, context);
+    }
+    return result;
+  }
+
+  @Override
+  protected boolean validateReferenceDetailValueLiteral(
+    EAnnotation eAnnotation,
+    EModelElement eModelElement,
+    Entry<String, String> entry,
+    EReference reference,
+    String literalValue,
+    List<Object> referenceValues,
+    DiagnosticChain diagnostics,
+    Map<Object, Object> context)
+  {
+    return getModelObject(context).validateEntryValueLiteral(this, entry, literalValue, referenceValues, diagnostics, context);
+  }
+
+  @Override
+  protected boolean validateFeatureDetailValue(
+    EAnnotation eAnnotation,
+    EModelElement eModelElement,
+    Entry<String, String> entry,
+    EStructuralFeature feature,
+    List<Object> values,
+    DiagnosticChain diagnostics,
+    Map<Object, Object> context)
+  {
+    return getModelObject(context).validateEntryValue(this, entry, values, diagnostics, context);
+  }
+
+  private ModelObject getModelObject(Map<Object, Object> context)
+  {
+    return (ModelObject)context.get(INSTANCE_VALUE);
+  }
+
+  public Collection<?> filterChoiceOfValues(EObject eObject, EStructuralFeature eStructuralFeature, Collection<?> choiceOfValues)
+  {
+    return ((ModelObject)eObject).filterChoiceOfValues(eStructuralFeature, choiceOfValues);
+  }
+
+  static class SpecializedExtendedMetaData extends BasicExtendedMetaData
+  {
+    private static final Map<ResourceSet, SpecializedExtendedMetaData> EXTENDED_META_DATA_CACHE = new WeakHashMap<ResourceSet, SpecializedExtendedMetaData>();
+
+    public static SpecializedExtendedMetaData getExtendedMetaData(EObject eObject)
+    {
+      synchronized (EXTENDED_META_DATA_CACHE)
+      {
+        ResourceSet resourceSet = null;
+        Resource resource = eObject.eResource();
+        if (resource != null)
+        {
+          resourceSet = resource.getResourceSet();
+        }
+
+        SpecializedExtendedMetaData specializedExtendedMetaData = EXTENDED_META_DATA_CACHE.get(resourceSet);
+        if (specializedExtendedMetaData == null)
+        {
+          if (resourceSet == null)
+          {
+            EPackageRegistryImpl registry = new EPackageRegistryImpl(EPackage.Registry.INSTANCE);
+            specializedExtendedMetaData = new SpecializedExtendedMetaData(registry);
+          }
+          else
+          {
+            specializedExtendedMetaData = new SpecializedExtendedMetaData(resourceSet.getPackageRegistry());
+          }
+          EXTENDED_META_DATA_CACHE.put(resourceSet, specializedExtendedMetaData);
+        }
+
+        return specializedExtendedMetaData;
+      }
+    }
+
+    public SpecializedExtendedMetaData(EPackage.Registry registry)
+    {
+      super(registry);
+      extendedMetaDataHolderCache = new HashMap<EModelElement, Object>()
+        {
+          private static final long serialVersionUID = 1L;
+
+          @Override
+          public Object put(EModelElement key, Object value)
+          {
+            // Don't cache anything.
+            return null;
+          }
+        };
+      putPackage(ExtendedMetaData.XML_SCHEMA_URI, getPackage(XMLTypePackage.eNS_URI));
+    }
+
+    @Override
+    protected boolean isFeatureKindSpecific()
+    {
+      return false;
+    }
+
+    @Override
+    protected boolean isFeatureNamespaceMatchingLax()
+    {
+      return true;
+    }
+
+    public void setDocumentRoot(EClass eClass, boolean documentRoot)
+    {
+      if (documentRoot)
+      {
+        setDocumentRoot(eClass);
+
+        EReference xmlnsPrefixMapFeature = getXMLNSPrefixMapFeature(eClass);
+        if (xmlnsPrefixMapFeature == null)
+        {
+          eClass.getEStructuralFeatures().add(EcoreUtil.copy(XMLTypePackage.Literals.XML_TYPE_DOCUMENT_ROOT__XMLNS_PREFIX_MAP));
+        }
+        EReference xsiSchemaLocationMapFeature = getXSISchemaLocationMapFeature(eClass);
+        if (xsiSchemaLocationMapFeature == null)
+        {
+          eClass.getEStructuralFeatures().add(EcoreUtil.copy(XMLTypePackage.Literals.XML_TYPE_DOCUMENT_ROOT__XSI_SCHEMA_LOCATION));
+        }
+      }
+      else
+      {
+        EAnnotation eAnnotation = getAnnotation(eClass, false);
+        if (eAnnotation != null)
+        {
+          eAnnotation.getDetails().removeKey("name");
+        }
+      }
+    }
+
+    @Override
+    public void setContentKind(EClass eClass, int kind)
+    {
+      super.setContentKind(eClass, kind);
+      if (kind == MIXED_CONTENT)
+      {
+        EAttribute mixedFeature = getMixedFeature(eClass);
+        if (mixedFeature == null)
+        {
+          eClass.getEStructuralFeatures().add(EcoreUtil.copy(XMLTypePackage.Literals.XML_TYPE_DOCUMENT_ROOT__MIXED));
+        }
+
+        for (EStructuralFeature eStructuralFeature : getElements(eClass))
+        {
+          eStructuralFeature.setUpperBound(ETypedElement.UNSPECIFIED_MULTIPLICITY);
+          eStructuralFeature.setDerived(true);
+          eStructuralFeature.setVolatile(true);
+          eStructuralFeature.setTransient(true);
+        }
+      }
+      else if (kind == SIMPLE_CONTENT)
+      {
+        EStructuralFeature simpleFeature = getSimpleFeature(eClass);
+        if (simpleFeature == null)
+        {
+          simpleFeature = EcoreFactory.eINSTANCE.createEAttribute();
+          simpleFeature.setName("simple");
+          simpleFeature.setEType(XMLTypePackage.Literals.STRING);
+          setFeatureKind(simpleFeature, SIMPLE_FEATURE);
+          eClass.getEStructuralFeatures().add(simpleFeature);
+        }
+      }
+    }
+
+    @Override
+    public void setFeatureKind(EStructuralFeature eStructuralFeature, int kind)
+    {
+      super.setFeatureKind(eStructuralFeature, kind);
+      if (kind == ELEMENT_WILDCARD_FEATURE || kind == ATTRIBUTE_WILDCARD_FEATURE || kind == GROUP_FEATURE)
+      {
+        if (eStructuralFeature instanceof EAttribute)
+        {
+          eStructuralFeature.setEType(EcorePackage.Literals.EFEATURE_MAP_ENTRY);
+        }
+      }
+    }
+
+    @Override
+    public void setNamespace(EStructuralFeature eStructuralFeature, String namespace)
+    {
+      super.setNamespace(eStructuralFeature, "".equals(namespace) ? null : namespace);
+    }
+
+    @Override
+    public void setItemType(EDataType eDataType, EDataType itemType)
+    {
+      super.setItemType(eDataType, itemType);
+      if (itemType != null)
+      {
+        super.setBaseType(eDataType, null);
+        super.setMemberTypes(eDataType, Collections.<EDataType> emptyList());
+      }
+    }
+
+    @Override
+    public void setBaseType(EDataType eDataType, EDataType baseType)
+    {
+      super.setBaseType(eDataType, baseType);
+      if (baseType != null)
+      {
+        super.setItemType(eDataType, null);
+        super.setMemberTypes(eDataType, Collections.<EDataType> emptyList());
+      }
+    }
+
+    @Override
+    public void setMemberTypes(EDataType eDataType, List<EDataType> memberTypes)
+    {
+      super.setMemberTypes(eDataType, memberTypes);
+      if (!memberTypes.isEmpty())
+      {
+        super.setBaseType(eDataType, null);
+        super.setItemType(eDataType, null);
+      }
+    }
+
+    @Override
+    public void setMinExclusiveFacet(EDataType eDataType, String literal)
+    {
+      super.setMinExclusiveFacet(eDataType, literal);
+      if (literal != null)
+      {
+        super.setMinInclusiveFacet(eDataType, null);
+      }
+    }
+
+    @Override
+    public void setMinInclusiveFacet(EDataType eDataType, String literal)
+    {
+      super.setMinInclusiveFacet(eDataType, literal);
+      if (literal != null)
+      {
+        super.setMinExclusiveFacet(eDataType, literal);
+      }
+    }
+
+    @Override
+    public void setMaxExclusiveFacet(EDataType eDataType, String literal)
+    {
+      super.setMaxExclusiveFacet(eDataType, literal);
+      if (literal != null)
+      {
+        super.setMaxInclusiveFacet(eDataType, null);
+      }
+    }
+
+    @Override
+    public void setMaxInclusiveFacet(EDataType eDataType, String literal)
+    {
+      super.setMaxInclusiveFacet(eDataType, literal);
+      if (literal != null)
+      {
+        super.setMaxExclusiveFacet(eDataType, literal);
+      }
+    }
+
+    @Override
+    public void setLengthFacet(EDataType eDataType, int length)
+    {
+      super.setLengthFacet(eDataType, length);
+      if (length != -1)
+      {
+        super.setMinLengthFacet(eDataType, -1);
+        super.setMaxLengthFacet(eDataType, -1);
+      }
+    }
+
+    @Override
+    public void setMinLengthFacet(EDataType eDataType, int length)
+    {
+      super.setMinLengthFacet(eDataType, length);
+      if (length != -1)
+      {
+        super.setLengthFacet(eDataType, -1);
+      }
+    }
+
+    @Override
+    public void setMaxLengthFacet(EDataType eDataType, int length)
+    {
+      super.setMaxLengthFacet(eDataType, length);
+      if (length != -1)
+      {
+        super.setLengthFacet(eDataType, -1);
+      }
+    }
+
+    protected ExtendedMetaDataAnnotationValidator getValidator(Map<Object, Object> context)
+    {
+      return (ExtendedMetaDataAnnotationValidator)context.get("EXTENDED_META_DATA_ANNOTATION_VALIDATOR");
+    }
+
+    protected BasicDiagnostic createDiagnostic(int severity, int code, String message, Object... data)
+    {
+      return new BasicDiagnostic(severity, DIAGNOSTIC_SOURCE, code, message, data);
+    }
+
+    protected void reportIgnoredEntry(Map.Entry<String, String> entry, DiagnosticChain diagnostics, String key, Object... substitutions)
+    {
+      diagnostics.add(
+        createDiagnostic(Diagnostic.WARNING, IGNORED_ENTRY, EcorePlugin.INSTANCE.getString(key, substitutions), entry, EcorePackage.Literals.ESTRING_TO_STRING_MAP_ENTRY__KEY));
+    }
+
+    protected void reportBadValue(Object value, DiagnosticChain diagnostics, int severity, String key, Object... substitutions)
+    {
+      diagnostics.add(createDiagnostic(severity, INVALID_VALUE_LITERAL, EcorePlugin.INSTANCE.getString(key, substitutions), value));
+    }
+
+    public boolean validateDataTypeEntry(EDataType eDataType, Map.Entry<String, String> entry, DiagnosticChain diagnostics, Map<Object, Object> context)
+    {
+      String key = entry.getKey();
+
+      Class<?> instanceClass = eDataType.getInstanceClass();
+      if (instanceClass == null && eDataType instanceof EEnum)
+      {
+        instanceClass = Enumerator.class;
+      }
+
+      if ("totalDigits".equals(key) || "fractionDigits".equals(key))
+      {
+        if (instanceClass != BigDecimal.class)
+        {
+          if (diagnostics != null)
+          {
+            reportIgnoredEntry(entry, diagnostics, "_UI_ExtendeMetaDataAnnotationDetailNotBigDecimal_diagnostic", key);
+          }
+          return false;
+        }
+        else
+        {
+          return true;
+        }
+      }
+      else if ("length".equals(key) || "maxLength".equals(key) || "minLength".equals(key))
+      {
+        boolean result = hasLength(instanceClass);
+        if (!result && diagnostics != null)
+        {
+          reportIgnoredEntry(entry, diagnostics, "_UI_ExtendeMetaDataAnnotationDetailNotHasLength_diagnostic", key);
+        }
+        return result;
+      }
+      else if ("itemType".equals(key))
+      {
+        boolean result = instanceClass == List.class;
+        if (!result && diagnostics != null)
+        {
+          reportIgnoredEntry(entry, diagnostics, "_UI_ExtendeMetaDataAnnotationDetailNotList_diagnostic", key);
+        }
+        return result;
+      }
+      else if ("baseType".equals(key))
+      {
+        boolean result = !(eDataType instanceof EEnum);
+        if (!result && diagnostics != null)
+        {
+          reportIgnoredEntry(entry, diagnostics, "_UI_ExtendeMetaDataAnnotationDetailNotRestrictEnum_diagnostic", key);
+        }
+        return result;
+      }
+      else if ("memberTypes".equals(key))
+      {
+        boolean result = !(eDataType instanceof EEnum);
+        if (!result && diagnostics != null)
+        {
+          reportIgnoredEntry(entry, diagnostics, "_UI_ExtendeMetaDataAnnotationDetailNotRestrictEnum_diagnostic", key);
+        }
+        return result;
+      }
+      else if ("maxInclusive".equals(key) || "maxExclusive".equals(key) || "minInclusive".equals(key) || "minExclusive".equals(key))
+      {
+        boolean result = instanceClass == null || isComparable(instanceClass);
+        if (!result && diagnostics != null)
+        {
+          reportIgnoredEntry(entry, diagnostics, "_UI_ExtendeMetaDataAnnotationDetailNotComparable_diagnostic", key);
+        }
+        else if (eDataType instanceof EEnum)
+        {
+          result = false;
+          if (!result && diagnostics != null)
+          {
+            reportIgnoredEntry(entry, diagnostics, "_UI_ExtendeMetaDataAnnotationDetailNotRestrictEnum_diagnostic", key);
+          }
+        }
+        return result;
+      }
+      else if ("enumeration".equals(key))
+      {
+        boolean result = !(eDataType instanceof EEnum);
+        if (!result && diagnostics != null)
+        {
+          reportIgnoredEntry(entry, diagnostics, "_UI_ExtendeMetaDataAnnotationDetailNotRestrictEnum_diagnostic", key);
+        }
+        return result;
+      }
+      else if ("pattern".equals(key))
+      {
+        boolean result = !(eDataType instanceof EEnum);
+        if (!result && diagnostics != null)
+        {
+          reportIgnoredEntry(entry, diagnostics, "_UI_ExtendeMetaDataAnnotationDetailNotRestrictEnum_diagnostic", key);
+        }
+        return result;
+      }
+      else if ("whiteSpace".equals(key))
+      {
+        boolean result = !(eDataType instanceof EEnum);
+        if (!result && diagnostics != null)
+        {
+          reportIgnoredEntry(entry, diagnostics, "_UI_ExtendeMetaDataAnnotationDetailNotRestrictEnum_diagnostic", key);
+        }
+        return result;
+      }
+      else
+      {
+        return true;
+      }
+    }
+
+    private boolean isComparable(Class<?> instanceClass)
+    {
+      if (instanceClass == null)
+      {
+        return true;
+      }
+      else
+      {
+        return instanceClass == Enumerator.class || Comparable.class.isAssignableFrom(EcoreUtil.wrapperClassFor(instanceClass));
+      }
+    }
+
+    private boolean hasLength(Class<?> instanceClass)
+    {
+      if (instanceClass == null)
+      {
+        return true;
+      }
+      else
+      {
+        return instanceClass == String.class || Collection.class.isAssignableFrom(instanceClass) || instanceClass.isArray();
+      }
+    }
+
+    public boolean validatePackageEntry(EPackage ePackage, Map.Entry<String, String> entry, DiagnosticChain diagnostics, Map<Object, Object> context)
+    {
+      return true;
+    }
+
+    public boolean validateClassEntry(EClass eClass, Map.Entry<String, String> entry, DiagnosticChain diagnostics, Map<Object, Object> context)
+    {
+      return true;
+    }
+
+    public boolean validateStructuralFeatureEntry(EStructuralFeature eStructuralFeature, Map.Entry<String, String> entry, DiagnosticChain diagnostics, Map<Object, Object> context)
+    {
+      String key = entry.getKey();
+      if ("affiliation".equals(key))
+      {
+        boolean result = true;
+        int featureKind = getFeatureKind(eStructuralFeature);
+        if (featureKind != ELEMENT_FEATURE || eStructuralFeature.getEContainingClass() == null || !isDocumentRoot(eStructuralFeature.getEContainingClass()))
+        {
+          result = false;
+        }
+        if (!result && diagnostics != null)
+        {
+          reportIgnoredEntry(entry, diagnostics, "_UI_ExtendeMetaDataAnnotationDetailNotGlobalElement_diagnostic", key);
+        }
+        return result;
+      }
+      else if ("processing".equals(key))
+      {
+        boolean result = true;
+        int featureKind = getFeatureKind(eStructuralFeature);
+        if (featureKind != ATTRIBUTE_WILDCARD_FEATURE && featureKind != ELEMENT_WILDCARD_FEATURE)
+        {
+          result = false;
+        }
+        if (!result && diagnostics != null)
+        {
+          reportIgnoredEntry(entry, diagnostics, "_UI_ExtendeMetaDataAnnotationDetailNotWildcard_diagnostic", key);
+        }
+        return result;
+      }
+      else if ("wildcards".equals(key))
+      {
+        boolean result = true;
+        int featureKind = getFeatureKind(eStructuralFeature);
+        if (featureKind != ATTRIBUTE_WILDCARD_FEATURE && featureKind != ELEMENT_WILDCARD_FEATURE)
+        {
+          result = false;
+        }
+        if (!result && diagnostics != null)
+        {
+          reportIgnoredEntry(entry, diagnostics, "_UI_ExtendeMetaDataAnnotationDetailNotWildcard_diagnostic", key);
+        }
+        return result;
+      }
+      else if ("namespace".equals(key))
+      {
+        boolean result = true;
+        int featureKind = getFeatureKind(eStructuralFeature);
+        if (featureKind != ELEMENT_FEATURE && featureKind != ATTRIBUTE_FEATURE && featureKind != GROUP_FEATURE)
+        {
+          result = false;
+        }
+        if (!result && diagnostics != null)
+        {
+          reportIgnoredEntry(entry, diagnostics, "_UI_ExtendeMetaDataAnnotationDetailNotElementAttributeOrGroup_diagnostic", key);
+        }
+        return result;
+      }
+      else
+      {
+        return true;
+      }
+    }
+
+    public boolean validateDataTypeEntryValueLiteral(
+      EDataType eDataType,
+      Map.Entry<String, String> entry,
+      String literalValue,
+      List<Object> values,
+      DiagnosticChain diagnostics,
+      Map<Object, Object> context)
+    {
+      String key = entry.getKey();
+      if ("baseType".equals(key) || "itemType".equals(key) || "memberTypes".equals(key))
+      {
+        EClassifier eClassifier = getEClassifier(eDataType.getEPackage(), literalValue);
+        if (eClassifier == null)
+        {
+          if (diagnostics != null)
+          {
+            reportBadValue(literalValue, diagnostics, Diagnostic.WARNING, "_UI_ExtendeMetaDataAnnotationDetailNotTypeResolved_diagnostic", literalValue);
+          }
+          return false;
+        }
+        else if (!(eClassifier instanceof EDataType))
+        {
+          if (diagnostics != null)
+          {
+            reportBadValue(literalValue, diagnostics, Diagnostic.WARNING, "_UI_ExtendeMetaDataAnnotationDetailNotTypeResolvedCorrectly_diagnostic", literalValue);
+          }
+          return false;
+        }
+        else
+        {
+          values.add(eClassifier);
+          return true;
+        }
+      }
+      else
+      {
+        return true;
+      }
+    }
+
+    public boolean validatePackageEntryValueLiteral(
+      EPackage ePackage,
+      Map.Entry<String, String> entry,
+      String literalValue,
+      List<Object> values,
+      DiagnosticChain diagnostics,
+      Map<Object, Object> context)
+    {
+      return true;
+    }
+
+    public boolean validateClassEntryValueLiteral(
+      EClass eClass,
+      Map.Entry<String, String> entry,
+      String literalValue,
+      List<Object> values,
+      DiagnosticChain diagnostics,
+      Map<Object, Object> context)
+    {
+      return true;
+    }
+
+    public boolean validateStructuralFeatureEntryValueLiteral(
+      EStructuralFeature eStructuralFeature,
+      Map.Entry<String, String> entry,
+      String literalValue,
+      List<Object> values,
+      DiagnosticChain diagnostics,
+      Map<Object, Object> context)
+    {
+      String key = entry.getKey();
+      if ("group".equals(key))
+      {
+        EStructuralFeature group = getGroup(eStructuralFeature);
+        if (group == null)
+        {
+          reportBadValue(literalValue, diagnostics, Diagnostic.WARNING, "_UI_ExtendeMetaDataAnnotationDetailNotGroupResolved_diagnostic", literalValue);
+          return false;
+        }
+        else
+        {
+          values.add(group);
+          return true;
+        }
+      }
+      else if ("affiliation".equals(key))
+      {
+        EStructuralFeature affiliation = getAffiliation(eStructuralFeature);
+        if (affiliation == null)
+        {
+          reportBadValue(literalValue, diagnostics, Diagnostic.WARNING, "_UI_ExtendeMetaDataAnnotationDetailNotAffiliationResolved_diagnostic", literalValue);
+          return false;
+        }
+        else
+        {
+          values.add(affiliation);
+          return true;
+        }
+      }
+      else
+      {
+        return true;
+      }
+    }
+
+    public boolean validateDataTypeEntryValue(EDataType eDataType, Map.Entry<String, String> entry, List<Object> values, DiagnosticChain diagnostics, Map<Object, Object> context)
+    {
+      String key = entry.getKey();
+      boolean result = true;
+      if ("baseType".equals(key) || "itemType".equals(key) || "memberTypes".equals(key))
+      {
+        for (Object value : values)
+        {
+          EDataType otherEDataType = (EDataType)value;
+          Set<EDataType> inheritedTypes = getInheritedTypes(otherEDataType);
+          if (inheritedTypes.contains(eDataType))
+          {
+            result = false;
+            if (diagnostics == null)
+            {
+              break;
+            }
+            else
+            {
+              reportBadValue(
+                inheritedTypes,
+                diagnostics,
+                Diagnostic.ERROR,
+                "_UI_ExtendeMetaDataAnnotationDetailTypeCircular_diagnostic",
+                getQualifiedName(getNamespace(eDataType), otherEDataType));
+            }
+          }
+        }
+      }
+      return result;
+    }
+
+    protected Set<EDataType> getInheritedTypes(EDataType eDataType)
+    {
+      Set<EDataType> typesToVisit = new LinkedHashSet<EDataType>();
+      Set<EDataType> result = new LinkedHashSet<EDataType>();
+      typesToVisit.add(eDataType);
+      do
+      {
+        Iterator<EDataType> it = typesToVisit.iterator();
+        EDataType dataType = it.next();
+        it.remove();
+        if (result.add(dataType))
+        {
+          EDataType baseType = getBaseType(dataType);
+          if (baseType != null)
+          {
+            typesToVisit.add(baseType);
+          }
+          EDataType itemType = getItemType(dataType);
+          if (itemType != null)
+          {
+            typesToVisit.add(itemType);
+          }
+          typesToVisit.addAll(getMemberTypes(dataType));
+        }
+      }
+      while (!typesToVisit.isEmpty());
+      return result;
+    }
+
+    public boolean validatePackageEntryValue(EPackage ePackage, Map.Entry<String, String> entry, List<Object> values, DiagnosticChain diagnostics, Map<Object, Object> context)
+    {
+      return true;
+    }
+
+    public boolean validateClassEntryValue(EClass eClass, Map.Entry<String, String> entry, List<Object> values, DiagnosticChain diagnostics, Map<Object, Object> context)
+    {
+      return true;
+    }
+
+    public boolean validateStructuralFeatureEntryValue(
+      EStructuralFeature eStructuralFeature,
+      Map.Entry<String, String> entry,
+      List<Object> values,
+      DiagnosticChain diagnostics,
+      Map<Object, Object> context)
+    {
+      String key = entry.getKey();
+      if ("group".equals(key))
+      {
+        EStructuralFeature group = (EStructuralFeature)values.get(0);
+        Set<EStructuralFeature> groups = getAffiliations(group);
+        if (groups.contains(eStructuralFeature))
+        {
+          reportBadValue(groups, diagnostics, Diagnostic.ERROR, "_UI_ExtendeMetaDataAnnotationDetailGroupCircular_diagnostic", getQualifiedName(getPackageNamespace(group), group));
+          return false;
+        }
+        else
+        {
+          return true;
+        }
+      }
+      else if ("affiliation".equals(key))
+      {
+        EStructuralFeature affiliation = (EStructuralFeature)values.get(0);
+        Set<EStructuralFeature> affiliations = getAffiliations(affiliation);
+        if (affiliations.contains(eStructuralFeature))
+        {
+          reportBadValue(
+            affiliations,
+            diagnostics,
+            Diagnostic.ERROR,
+            "_UI_ExtendeMetaDataAnnotationDetailAffiliationCircular_diagnostic",
+            getQualifiedName(getPackageNamespace(affiliation), affiliation));
+          return false;
+        }
+        else
+        {
+          return true;
+        }
+      }
+      else
+      {
+        return true;
+      }
+    }
+
+    protected Set<EStructuralFeature> getAffiliations(EStructuralFeature eStructuralFeature)
+    {
+      Set<EStructuralFeature> result = new LinkedHashSet<EStructuralFeature>();
+      for (EStructuralFeature affiliation = eStructuralFeature; affiliation != null; affiliation = getAffiliation(affiliation))
+      {
+        if (!result.add(affiliation))
+        {
+          break;
+        }
+      }
+      return result;
+    }
+
+    protected Set<EStructuralFeature> getGroups(EStructuralFeature eStructuralFeature)
+    {
+      Set<EStructuralFeature> result = new LinkedHashSet<EStructuralFeature>();
+      for (EStructuralFeature group = eStructuralFeature; group != null; group = getGroup(group))
+      {
+        if (!result.add(group))
+        {
+          break;
+        }
+      }
+      return result;
+    }
+  }
+
+  private static class ModelObject extends MinimalEObjectImpl.Container.Dynamic
+  {
+    protected SpecializedExtendedMetaData extendedMetaData;
+
+    protected ENamedElement eNamedElement;
+
+    public void setElement(ENamedElement eNamedElement)
+    {
+      if (ExtendedMetaDataAnnotationValidator.INSTANCE.getPropertyClass(eNamedElement) != eClass())
+      {
+        throw new IllegalArgumentException();
+      }
+
+      extendedMetaData = SpecializedExtendedMetaData.getExtendedMetaData(eNamedElement);
+
+      this.eNamedElement = eNamedElement;
+    }
+
+    @Override
+    public Object eGet(EStructuralFeature eStructuralFeature)
+    {
+      EClassifier eType = eStructuralFeature.getEType();
+      String name = eStructuralFeature.getName();
+      Method method = PropertySwitch.GETTERS.get(eStructuralFeature);
+      try
+      {
+        Object result = method.invoke(extendedMetaData, eNamedElement);
+        if (name.equals("wildcards"))
+        {
+          @SuppressWarnings("unchecked")
+          EList<String> wildcards = ECollections.asEList((List<String>)result);
+          int index = wildcards.indexOf(null);
+          if (index != -1)
+          {
+            wildcards.set(index, "##local");
+          }
+          return wildcards;
+        }
+        else
+        {
+          return eType instanceof EEnum ? ((EEnum)eType).getEEnumLiteral((Integer)result) : eStructuralFeature.isMany() ? ECollections.asEList((List<?>)result) : result;
+        }
+      }
+      catch (Exception exception)
+      {
+        throw new RuntimeException(exception);
+      }
+    }
+
+    @Override
+    public void eSet(EStructuralFeature eStructuralFeature, Object value)
+    {
+      Method method = PropertySwitch.SETTERS.get(eStructuralFeature);
+      try
+      {
+        if (value instanceof Enumerator)
+        {
+          method.invoke(extendedMetaData, eNamedElement, ((Enumerator)value).getValue());
+        }
+        else
+        {
+          method.invoke(extendedMetaData, eNamedElement, value);
+        }
+      }
+      catch (Exception exception)
+      {
+        throw new RuntimeException(exception);
+      }
+    }
+
+    @Override
+    public void eUnset(EStructuralFeature eStructuralFeature)
+    {
+      EAnnotation eAnnotation = eNamedElement.getEAnnotation(ExtendedMetaData.ANNOTATION_URI);
+      if (eAnnotation != null)
+      {
+        eAnnotation.getDetails().removeKey(eStructuralFeature.getName());
+      }
+    }
+
+    @Override
+    public boolean eIsSet(EStructuralFeature eStructuralFeature)
+    {
+      EAnnotation eAnnotation = eNamedElement.getEAnnotation(ExtendedMetaData.ANNOTATION_URI);
+      return eAnnotation != null && eAnnotation.getDetails().get(eStructuralFeature.getName()) != null;
+    }
+
+    public boolean isApplicable(EStructuralFeature eStructuralFeature)
+    {
+      Method method = PropertySwitch.ENTRY_VALIDATORS.get(eClass);
+      EMap<String, String> details = EcoreFactory.eINSTANCE.createEAnnotation().getDetails();
+      details.put(eStructuralFeature.getName(), null);
+      try
+      {
+        return (Boolean)method.invoke(extendedMetaData, eNamedElement, details.get(0), null, null);
+      }
+      catch (Exception exception)
+      {
+        throw new RuntimeException(exception);
+      }
+    }
+
+    public Collection<?> filterChoiceOfValues(EStructuralFeature eStructuralFeature, Collection<?> choiceOfValues)
+    {
+      List<Object> result = new ArrayList<Object>();
+      if (choiceOfValues != null)
+      {
+        result.addAll(choiceOfValues);
+      }
+
+      String name = eStructuralFeature.getName();
+      if (name.equals("kind"))
+      {
+        if (eStructuralFeature.getEContainingClass().getName().equals("StructuralFeature"))
+        {
+          if (eNamedElement instanceof EReference)
+          {
+            for (Object object : choiceOfValues)
+            {
+              String literal = object.toString();
+              if (literal.equals("group") || literal.equals("elementWildcard") || literal.equals("attributeWildcard"))
+              {
+                result.remove(object);
+              }
+            }
+          }
+        }
+      }
+      else if (name.equals("namespace"))
+      {
+        EStructuralFeature targetFeature = (EStructuralFeature)eNamedElement;
+        for (Object object : choiceOfValues)
+        {
+          result.remove(object);
+          if (object instanceof EPackage)
+          {
+            EPackage ePackage = (EPackage)object;
+            String namespace = extendedMetaData.getNamespace(ePackage);
+            if (namespace != null)
+            {
+              int featureKind = extendedMetaData.getFeatureKind(targetFeature);
+              String targetName = extendedMetaData.getName(targetFeature);
+              EStructuralFeature element = featureKind == ExtendedMetaData.ELEMENT_FEATURE
+                ? extendedMetaData.getElement(namespace, targetName)
+                : featureKind == ExtendedMetaData.ATTRIBUTE_FEATURE ? extendedMetaData.getAttribute(namespace, targetName) : null;
+              if (element != null)
+              {
+                result.add(namespace);
+              }
+            }
+          }
+        }
+        String targetNamespace = extendedMetaData.getNamespace(targetFeature);
+        if (targetNamespace != null && !"".equals(targetNamespace) && !result.contains(targetNamespace))
+        {
+          result.add(targetNamespace);
+        }
+        EClass eContainingClass = targetFeature.getEContainingClass();
+        if (eContainingClass != null)
+        {
+          String namespace = extendedMetaData.getNamespace(eContainingClass);
+          if (namespace != null && !"".equals(namespace) && !result.contains(namespace))
+          {
+            result.add(namespace);
+          }
+        }
+        result.add("");
+      }
+      else if (name.equals("wildcards"))
+      {
+        for (Object object : choiceOfValues)
+        {
+          result.remove(object);
+          if (object instanceof EPackage)
+          {
+            EPackage ePackage = (EPackage)object;
+            if (extendedMetaData.getDocumentRoot(ePackage) != null)
+            {
+              String namespace = extendedMetaData.getNamespace(ePackage);
+              if (!XMLTypePackage.eNS_URI.equals(namespace))
+              {
+                result.add(namespace);
+              }
+            }
+          }
+        }
+
+        EStructuralFeature targetFeature = (EStructuralFeature)eNamedElement;
+        EClass eContainingClass = targetFeature.getEContainingClass();
+        if (eContainingClass != null)
+        {
+          String namespace = extendedMetaData.getNamespace(eContainingClass);
+          result.add("!##" + namespace);
+        }
+
+        result.add("##any");
+        result.add("##local");
+      }
+      else if (name.equals("group"))
+      {
+        result.clear();
+        for (EAttribute eAttribute : ((EStructuralFeature)eNamedElement).getEContainingClass().getEAllAttributes())
+        {
+          if (extendedMetaData.getFeatureKind(eAttribute) == ExtendedMetaData.GROUP_FEATURE && eAttribute != eNamedElement)
+          {
+            result.add(eAttribute);
+          }
+        }
+        result.add(null);
+      }
+      else if (name.equals("affiliation"))
+      {
+        EStructuralFeature targetFeature = (EStructuralFeature)eNamedElement;
+        EClassifier eType = targetFeature.getEType();
+        for (Object object : choiceOfValues)
+        {
+          if (object instanceof EStructuralFeature)
+          {
+            EStructuralFeature feature = (EStructuralFeature)object;
+            EClass eContainingClass = feature.getEContainingClass();
+            if (eType == null || eContainingClass == null || !extendedMetaData.isDocumentRoot(eContainingClass)
+              || XMLTypePackage.eNS_URI.equals(extendedMetaData.getNamespace(eContainingClass)) || extendedMetaData.getFeatureKind(feature) != ExtendedMetaData.ELEMENT_FEATURE
+              || !isSuperTypeOf(feature.getEType(), eType))
+            {
+              result.remove(object);
+            }
+            else
+            {
+              Set<EStructuralFeature> affiliations = new LinkedHashSet<EStructuralFeature>();
+              for (EStructuralFeature affiliation = feature; affiliation != null && affiliations.add(affiliation); affiliation = extendedMetaData.getAffiliation(affiliation))
+              {
+                if (targetFeature == affiliation)
+                {
+                  result.remove(object);
+                  break;
+                }
+              }
+            }
+          }
+        }
+        // Always add the current value, even if it's not valid.
+        EStructuralFeature affiliation = extendedMetaData.getAffiliation(targetFeature);
+        if (affiliation != null && !result.contains(affiliation))
+        {
+          result.add(affiliation);
+        }
+      }
+      else if (name.equals("baseType"))
+      {
+        EDataType eDataType = (EDataType)eNamedElement;
+        for (Object object : choiceOfValues)
+        {
+          if (object instanceof EDataType)
+          {
+            EDataType dataType = (EDataType)object;
+            if (!isSuperTypeOf(eDataType, dataType))
+            {
+              result.remove(object);
+            }
+            else if (eDataType.isSerializable() && !dataType.isSerializable())
+            {
+              result.remove(object);
+            }
+            else if (extendedMetaData.getInheritedTypes(dataType).contains(eDataType))
+            {
+              result.remove(object);
+            }
+          }
+        }
+      }
+      else if (name.equals("itemType"))
+      {
+        EDataType eDataType = (EDataType)eNamedElement;
+        for (Object object : choiceOfValues)
+        {
+          if (object instanceof EDataType)
+          {
+            EDataType dataType = (EDataType)object;
+            Class<?> instanceClass = dataType.getInstanceClass();
+            if (instanceClass != null && Collection.class.isAssignableFrom(instanceClass))
+            {
+              result.remove(object);
+            }
+            else if (eDataType.isSerializable() && !dataType.isSerializable())
+            {
+              result.remove(object);
+            }
+            else if (extendedMetaData.getInheritedTypes(dataType).contains(eDataType))
+            {
+              result.remove(object);
+            }
+          }
+        }
+      }
+      else if (name.equals("memberTypes"))
+      {
+        EDataType eDataType = (EDataType)eNamedElement;
+        for (Object object : choiceOfValues)
+        {
+          if (object instanceof EDataType)
+          {
+            EDataType dataType = (EDataType)object;
+            if (!isSuperTypeOf(eDataType, dataType))
+            {
+              result.remove(object);
+            }
+            else if (eDataType.isSerializable() && !dataType.isSerializable())
+            {
+              result.remove(object);
+            }
+            else if (extendedMetaData.getInheritedTypes(dataType).contains(eDataType))
+            {
+              result.remove(object);
+            }
+          }
+        }
+      }
+
+      return choiceOfValues == null && result.isEmpty() ? null : result;
+    }
+
+    private boolean isSuperTypeOf(EClassifier eClassifier1, EClassifier eClassifier2)
+    {
+      if (eClassifier1 instanceof EClass && eClassifier2 instanceof EClass)
+      {
+        EClass eClass1 = (EClass)eClassifier1;
+        EClass eClass2 = (EClass)eClassifier2;
+        return eClass1.isSuperTypeOf(eClass2);
+      }
+      else if (eClassifier1 instanceof EDataType && eClassifier2 instanceof EDataType)
+      {
+        EDataType eDataType1 = (EDataType)eClassifier1;
+        EDataType eDataType2 = (EDataType)eClassifier2;
+        Class<?> instanceClass1 = eDataType1.getInstanceClass();
+        Class<?> instanceClass2 = eDataType2.getInstanceClass();
+        if (instanceClass1 == null || instanceClass2 == null)
+        {
+          return true;
+        }
+        else
+        {
+          return instanceClass1.isAssignableFrom(instanceClass2);
+        }
+      }
+      else
+      {
+        return false;
+      }
+    }
+
+    private boolean isSuperTypeOf(EDataType eDataType1, EDataType eDataType2)
+    {
+      Class<?> instanceClass1 = eDataType1.getInstanceClass();
+      if (instanceClass1 == null && eDataType1 instanceof EEnum)
+      {
+        instanceClass1 = Enumerator.class;
+      }
+      Class<?> instanceClass2 = eDataType2.getInstanceClass();
+      if (instanceClass2 == null && eDataType2 instanceof EEnum)
+      {
+        instanceClass2 = Enumerator.class;
+      }
+      if (instanceClass1 == null || instanceClass2 == null)
+      {
+        return true;
+      }
+      else
+      {
+        return instanceClass1.isAssignableFrom(instanceClass2) || instanceClass1.isAssignableFrom(EcoreUtil.wrapperClassFor(instanceClass2));
+      }
+    }
+
+    public boolean validateEntry(
+      ExtendedMetaDataAnnotationValidator extendedMetaDataAnnotationValidator,
+      Map.Entry<String, String> entry,
+      DiagnosticChain diagnostics,
+      Map<Object, Object> context)
+    {
+      boolean result = true;
+      try
+      {
+        Method method = PropertySwitch.ENTRY_VALIDATORS.get(eClass);
+        result = (Boolean)method.invoke(extendedMetaData, eNamedElement, entry, diagnostics, context);
+      }
+      catch (Exception exception)
+      {
+        throw new RuntimeException(exception);
+      }
+      return result;
+    }
+
+    public boolean validateEntryValueLiteral(
+      ExtendedMetaDataAnnotationValidator extendedMetaDataAnnotationValidator,
+      Map.Entry<String, String> entry,
+      String literalValue,
+      List<Object> referenceValues,
+      DiagnosticChain diagnostics,
+      Map<Object, Object> context)
+    {
+      boolean result = true;
+      try
+      {
+        Method method = PropertySwitch.ENTRY_VALUE_LITERAL_VALIDATORS.get(eClass);
+        result = (Boolean)method.invoke(extendedMetaData, eNamedElement, entry, literalValue, referenceValues, diagnostics, context);
+      }
+      catch (Exception exception)
+      {
+        throw new RuntimeException(exception);
+      }
+      return result;
+    }
+
+    public boolean validateEntryValue(
+      ExtendedMetaDataAnnotationValidator extendedMetaDataAnnotationValidator,
+      Map.Entry<String, String> entry,
+      List<Object> values,
+      DiagnosticChain diagnostics,
+      Map<Object, Object> context)
+    {
+      boolean result = true;
+      try
+      {
+        Method method = PropertySwitch.ENTRY_VALUE_VALIDATORS.get(eClass);
+        result = (Boolean)method.invoke(extendedMetaData, eNamedElement, entry, values, diagnostics, context);
+      }
+      catch (Exception exception)
+      {
+        throw new RuntimeException(exception);
+      }
+      return result;
+    }
+  }
+
+  private static abstract class PropertySwitch extends EcoreSwitch<Void>
+  {
+    private static final EPackage EXTENDED_META_DATA_PACKAGE;
+
+    private static final Map<EStructuralFeature, Method> GETTERS = new HashMap<EStructuralFeature, Method>();
+
+    private static final Map<EStructuralFeature, Method> SETTERS = new HashMap<EStructuralFeature, Method>();
+
+    private static final Map<EClass, Method> ENTRY_VALIDATORS = new HashMap<EClass, Method>();
+
+    private static final Map<EClass, Method> ENTRY_VALUE_LITERAL_VALIDATORS = new HashMap<EClass, Method>();
+
+    private static final Map<EClass, Method> ENTRY_VALUE_VALIDATORS = new HashMap<EClass, Method>();
+
+    static
+    {
+      URL baseURL = EcorePlugin.INSTANCE.getBaseURL();
+      URI baseURI = URI.createURI(baseURL + "/model/ExtendedMetaData.ecore");
+      EPackage ePackage = null;
+      try
+      {
+        Resource resource = new EPackageImpl()
+          {
+            @Override
+            public Resource createResource(String uri)
+            {
+              return super.createResource(uri);
+            }
+          }.createResource(baseURI.toString());
+        resource.unload();
+        resource.load(null);
+        ePackage = (EPackage)resource.getContents().get(0);
+      }
+      catch (Exception ex)
+      {
+        // Ignore.
+      }
+
+      EXTENDED_META_DATA_PACKAGE = ePackage;
+      if (ePackage != null)
+      {
+        final EClassifier xmlPatternDataType = ePackage.getEClassifier("Pattern");
+        EObjectValidator eObjectValidator = new EObjectValidator()
+          {
+            @Override
+            public boolean validate(EDataType eDataType, Object value, DiagnosticChain diagnostics, Map<Object, Object> context)
+            {
+              boolean result = super.validate(eDataType, value, diagnostics, context);
+              if (eDataType == xmlPatternDataType && result && value != null)
+              {
+                try
+                {
+                  XMLTypeUtil.createPatternMatcher((String)value);
+                }
+                catch (RuntimeException exception)
+                {
+                  result = false;
+                  if (diagnostics != null)
+                  {
+                    diagnostics.add(
+                      createDiagnostic(
+                        Diagnostic.ERROR,
+                        ExtendedMetaDataAnnotationValidator.DIAGNOSTIC_SOURCE,
+                        0,
+                        "_UI_BadXMLPattern_diagnostic",
+                        new Object []{ getValueLabel(eDataType, value, context), exception.getLocalizedMessage() },
+                        new Object []{ value, eDataType },
+                        context));
+                  }
+                }
+              }
+              return result;
+            }
+          };
+        EValidator.Registry.INSTANCE.put(ePackage, eObjectValidator);
+        ePackage.setEFactoryInstance(new EFactoryImpl()
+          {
+            @Override
+            protected EObject basicCreate(EClass eClass)
+            {
+              ModelObject result = new ModelObject();
+              result.eSetClass(eClass);
+              return result;
+            }
+          });
+
+        Method[] methods = SpecializedExtendedMetaData.class.getMethods();
+        for (EClassifier eClassifier : ePackage.getEClassifiers())
+        {
+          if (eClassifier instanceof EClass)
+          {
+            EClass eClass = (EClass)eClassifier;
+            if (!eClass.isAbstract())
+            {
+              ENTRY_VALIDATORS.put(eClass, getMethod(methods, eClass, "validate" + eClass.getName() + "Entry", 4));
+              ENTRY_VALUE_LITERAL_VALIDATORS.put(eClass, getMethod(methods, eClass, "validate" + eClass.getName() + "EntryValueLiteral", 6));
+              ENTRY_VALUE_VALIDATORS.put(eClass, getMethod(methods, eClass, "validate" + eClass.getName() + "EntryValue", 5));
+            }
+            for (EStructuralFeature eStructuralFeature : eClass.getEAllStructuralFeatures())
+            {
+              EClass eContainingClass = eStructuralFeature.getEContainingClass();
+              String accessor = EcoreUtil.getAnnotation(eStructuralFeature, "Reflection", "accessor");
+              GETTERS.put(
+                eStructuralFeature,
+                getMethod(methods, eContainingClass, ("boolean".equals(eStructuralFeature.getEType().getInstanceClassName()) ? "is" : "get") + accessor, 1));
+              SETTERS.put(eStructuralFeature, getMethod(methods, eContainingClass, "set" + accessor, 2));
+            }
+          }
+        }
+      }
+    }
+
+    private static Method getMethod(Method[] methods, EClass eClass, String expectedName, int expectedCount)
+    {
+      for (Method method : methods)
+      {
+        String name = method.getName();
+        if (name.equals(expectedName) && method.getParameterCount() == expectedCount && method.getParameterTypes()[0].getName().endsWith(eClass.getName()))
+        {
+          return method;
+        }
+      }
+
+      throw new IllegalStateException();
+    }
+
+    protected abstract void addFeatures(EClass eClass);
+
+    @Override
+    public Void caseEPackage(EPackage object)
+    {
+      if (EXTENDED_META_DATA_PACKAGE != null)
+      {
+        addFeatures((EClass)EXTENDED_META_DATA_PACKAGE.getEClassifier("Package"));
+      }
+      return null;
+    }
+
+    @Override
+    public Void caseEClass(EClass eClass)
+    {
+      if (EXTENDED_META_DATA_PACKAGE != null)
+      {
+        addFeatures((EClass)EXTENDED_META_DATA_PACKAGE.getEClassifier("Class"));
+      }
+      return null;
+    }
+
+    @Override
+    public Void caseEDataType(EDataType eDataType)
+    {
+      if (EXTENDED_META_DATA_PACKAGE != null)
+      {
+        addFeatures((EClass)EXTENDED_META_DATA_PACKAGE.getEClassifier("DataType"));
+      }
+      return null;
+    }
+
+    @Override
+    public Void caseEStructuralFeature(EStructuralFeature eStructuralFeature)
+    {
+      if (EXTENDED_META_DATA_PACKAGE != null)
+      {
+        addFeatures((EClass)EXTENDED_META_DATA_PACKAGE.getEClassifier("StructuralFeature"));
+      }
+      return null;
+    }
+  }
+}
diff --git a/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/xml/type/internal/RegEx.java b/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/xml/type/internal/RegEx.java
index aedfe3d..08887f4 100644
--- a/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/xml/type/internal/RegEx.java
+++ b/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/xml/type/internal/RegEx.java
@@ -60,7 +60,7 @@
 /**
  * NOTE: this class is for internal use only.
  */
-@SuppressWarnings({"rawtypes", "unchecked"})
+@SuppressWarnings("all")
 public final class RegEx
 {
 
diff --git a/plugins/org.eclipse.emf.edit.ui/icons/full/ctool16/Ellipses.gif b/plugins/org.eclipse.emf.edit.ui/icons/full/ctool16/Ellipses.gif
new file mode 100644
index 0000000..00e2ef0
--- /dev/null
+++ b/plugins/org.eclipse.emf.edit.ui/icons/full/ctool16/Ellipses.gif
Binary files differ
diff --git a/plugins/org.eclipse.emf.edit.ui/icons/full/ctool16/EncodedEllipses.gif b/plugins/org.eclipse.emf.edit.ui/icons/full/ctool16/EncodedEllipses.gif
new file mode 100644
index 0000000..144571f
--- /dev/null
+++ b/plugins/org.eclipse.emf.edit.ui/icons/full/ctool16/EncodedEllipses.gif
Binary files differ
diff --git a/plugins/org.eclipse.emf.edit.ui/icons/full/dlcl16/SetProperty.png b/plugins/org.eclipse.emf.edit.ui/icons/full/dlcl16/SetProperty.png
new file mode 100644
index 0000000..0c4f2a3
--- /dev/null
+++ b/plugins/org.eclipse.emf.edit.ui/icons/full/dlcl16/SetProperty.png
Binary files differ
diff --git a/plugins/org.eclipse.emf.edit.ui/icons/full/elcl16/SetProperty.png b/plugins/org.eclipse.emf.edit.ui/icons/full/elcl16/SetProperty.png
new file mode 100644
index 0000000..86551ca
--- /dev/null
+++ b/plugins/org.eclipse.emf.edit.ui/icons/full/elcl16/SetProperty.png
Binary files differ
diff --git a/plugins/org.eclipse.emf.edit.ui/plugin.properties b/plugins/org.eclipse.emf.edit.ui/plugin.properties
index 3539a48..3680484 100644
--- a/plugins/org.eclipse.emf.edit.ui/plugin.properties
+++ b/plugins/org.eclipse.emf.edit.ui/plugin.properties
@@ -33,6 +33,7 @@
 _UI_Feature_label = &Feature
 _UI_Value_label = &Value
 _UI_Choices_label = &Choices
+_UI_ValueAndChoices_label = &Value and Choices
 _UI_Choices_pattern_group = Filter Available Choices
 _UI_Choices_pattern_label = Choice &Pattern (* or ?)
 _UI_Up_label = &Up
@@ -60,6 +61,9 @@
 _UI_LocateValue_action = &Locate Value
 _UI_LocateValue_action_tool_tip = Locate Value
 
+_UI_SetValue_action = &Set Value
+_UI_SetValue_action_tool_tip = Set Value
+
 _UI_ValidationResults_title = Validation Information
 _UI_ValidationResults_message = Information encountered during validation
 
@@ -88,3 +92,5 @@
 _UI_DiagnosisOfNObjects_message = Diagnosis of {0} objects
 
 _UI_QueryDelegateTextViewerFactory_extensionpoint = Registered Query Delegate Text Viewer Factories
+
+_UI_DuplicateValue_message = The feature already contains this value
diff --git a/plugins/org.eclipse.emf.edit.ui/src/org/eclipse/emf/edit/ui/celleditor/FeatureEditorDialog.java b/plugins/org.eclipse.emf.edit.ui/src/org/eclipse/emf/edit/ui/celleditor/FeatureEditorDialog.java
index c617ac3..7b1b76e 100644
--- a/plugins/org.eclipse.emf.edit.ui/src/org/eclipse/emf/edit/ui/celleditor/FeatureEditorDialog.java
+++ b/plugins/org.eclipse.emf.edit.ui/src/org/eclipse/emf/edit/ui/celleditor/FeatureEditorDialog.java
@@ -1,4 +1,5 @@
 /**
+ *
  * Copyright (c) 2002-2009 IBM Corporation and others.
  * All rights reserved.   This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
@@ -12,23 +13,28 @@
 
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
-import java.util.Iterator;
 import java.util.List;
-import java.util.ListIterator;
 
 import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.resource.JFaceColors;
 import org.eclipse.jface.viewers.AbstractTreeViewer;
 import org.eclipse.jface.viewers.DoubleClickEvent;
 import org.eclipse.jface.viewers.IContentProvider;
 import org.eclipse.jface.viewers.IDoubleClickListener;
 import org.eclipse.jface.viewers.ILabelProvider;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
 import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
 import org.eclipse.jface.viewers.StructuredSelection;
 import org.eclipse.jface.viewers.TableViewer;
 import org.eclipse.jface.viewers.Viewer;
 import org.eclipse.jface.viewers.ViewerFilter;
 import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.FocusAdapter;
+import org.eclipse.swt.events.FocusEvent;
 import org.eclipse.swt.events.KeyAdapter;
 import org.eclipse.swt.events.KeyEvent;
 import org.eclipse.swt.events.ModifyEvent;
@@ -47,7 +53,6 @@
 import org.eclipse.swt.widgets.Table;
 import org.eclipse.swt.widgets.Text;
 import org.eclipse.ui.dialogs.PatternFilter;
-
 import org.eclipse.emf.common.notify.AdapterFactory;
 import org.eclipse.emf.common.notify.impl.AdapterFactoryImpl;
 import org.eclipse.emf.common.ui.celleditor.ExtendedComboBoxCellEditor;
@@ -58,8 +63,10 @@
 import org.eclipse.emf.ecore.EObject;
 import org.eclipse.emf.ecore.EReference;
 import org.eclipse.emf.ecore.EStructuralFeature;
-import org.eclipse.emf.ecore.util.EcoreUtil;
 import org.eclipse.emf.edit.provider.ComposedAdapterFactory;
+import org.eclipse.emf.edit.provider.IItemPropertyDescriptor;
+import org.eclipse.emf.edit.provider.IItemPropertyDescriptor.ValueHandler;
+import org.eclipse.emf.edit.provider.ItemPropertyDescriptor;
 import org.eclipse.emf.edit.provider.ItemProvider;
 import org.eclipse.emf.edit.ui.EMFEditUIPlugin;
 import org.eclipse.emf.edit.ui.provider.AdapterFactoryContentProvider;
@@ -79,21 +86,28 @@
   protected boolean unique;
 
   /**
-   * @since 2.6
+   * @since 2.14
+   */
+  protected ValueHandler valueHandler;
+
+  /**
+   * @since 2.14
    */
   public FeatureEditorDialog
-    (Shell parent, 
-     ILabelProvider labelProvider, 
-     Object object, 
-     EClassifier eClassifier, 
-     List<?> currentValues, 
-     String displayName, 
+    (Shell parent,
+     ILabelProvider labelProvider,
+     Object object,
+     EClassifier eClassifier,
+     List<?> currentValues,
+     String displayName,
      List<?> choiceOfValues,
      boolean multiLine,
      boolean sortChoices,
-     boolean unique)
+     boolean unique,
+     IItemPropertyDescriptor.ValueHandler valueHandler)
   {
     super(parent);
+    this.valueHandler = valueHandler;
     setShellStyle(getShellStyle() | SWT.RESIZE | SWT.MAX);
     this.labelProvider = labelProvider;
     this.object = object;
@@ -114,18 +128,36 @@
   }
 
   /**
+   * @since 2.6
+   */
+  public FeatureEditorDialog
+    (Shell parent,
+     ILabelProvider labelProvider,
+     Object object,
+     EClassifier eClassifier,
+     List<?> currentValues,
+     String displayName,
+     List<?> choiceOfValues,
+     boolean multiLine,
+     boolean sortChoices,
+     boolean unique)
+  {
+    this(parent, labelProvider, object, eClassifier, currentValues, displayName, choiceOfValues, multiLine, sortChoices, unique, null);
+  }
+
+  /**
    * @deprecated Use {@link #FeatureEditorDialog(Shell, ILabelProvider, Object, EClassifier, List, String, List, boolean, boolean, boolean)},
    * which provides proper behaviour for unique and non-unique features. This form retains the old behaviour, where
    * specifying a list of choices enforces uniqueness.
    */
   @Deprecated
   public FeatureEditorDialog
-  (Shell parent, 
-   ILabelProvider labelProvider, 
-   Object object, 
-   EClassifier eClassifier, 
-   List<?> currentValues, 
-   String displayName, 
+  (Shell parent,
+   ILabelProvider labelProvider,
+   Object object,
+   EClassifier eClassifier,
+   List<?> currentValues,
+   String displayName,
    List<?> choiceOfValues,
    boolean multiLine,
    boolean sortChoices)
@@ -140,23 +172,23 @@
    */
   @Deprecated
   public FeatureEditorDialog
-    (Shell parent, 
-     ILabelProvider labelProvider, 
-     Object object, 
-     EClassifier eClassifier, 
-     List<?> currentValues, 
-     String displayName, 
+    (Shell parent,
+     ILabelProvider labelProvider,
+     Object object,
+     EClassifier eClassifier,
+     List<?> currentValues,
+     String displayName,
      List<?> choiceOfValues)
   {
     this(parent, labelProvider, object, eClassifier, currentValues, displayName, choiceOfValues, false, false, choiceOfValues != null);
   }
 
   public FeatureEditorDialog
-    (Shell parent, 
-     ILabelProvider labelProvider, 
-     EObject eObject, 
-     EStructuralFeature eStructuralFeature, 
-     String displayName, 
+    (Shell parent,
+     ILabelProvider labelProvider,
+     EObject eObject,
+     EStructuralFeature eStructuralFeature,
+     String displayName,
      List<?> choiceOfValues)
   {
     this(parent,
@@ -172,7 +204,7 @@
   }
 
   @Override
-  protected void configureShell(Shell shell) 
+  protected void configureShell(Shell shell)
   {
     super.configureShell(shell);
     shell.setText
@@ -182,7 +214,7 @@
   }
 
   @Override
-  protected Control createDialogArea(Composite parent) 
+  protected Control createDialogArea(Composite parent)
   {
     Composite contents = (Composite)super.createDialogArea(parent);
 
@@ -195,7 +227,7 @@
 
     Text patternText = null;
 
-    if (choiceOfValues != null) 
+    if (choiceOfValues != null)
     {
       Group filterGroupComposite = new Group(contents, SWT.NONE);
       filterGroupComposite.setText(EMFEditUIPlugin.INSTANCE.getString("_UI_Choices_pattern_group"));
@@ -225,14 +257,42 @@
 
     Label choiceLabel = new Label(choiceComposite, SWT.NONE);
     choiceLabel.setText
-      (choiceOfValues == null ? 
-         EMFEditUIPlugin.INSTANCE.getString("_UI_Value_label") : 
-         EMFEditUIPlugin.INSTANCE.getString("_UI_Choices_label"));
+       (EMFEditUIPlugin.INSTANCE.getString
+           (choiceOfValues == null ?
+               "_UI_Value_label" :
+                  valueHandler == null ?
+                    "_UI_Choices_label" :
+                    "_UI_ValueAndChoices_label"));
     GridData choiceLabelGridData = new GridData();
     choiceLabelGridData.verticalAlignment = SWT.FILL;
     choiceLabelGridData.horizontalAlignment = SWT.FILL;
     choiceLabel.setLayoutData(choiceLabelGridData);
 
+    // We use multi even for a single line because we want to respond to the enter key.
+    //
+    int style = multiLine ?
+      SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER :
+      SWT.MULTI | SWT.BORDER;
+    final Text choiceText = choiceOfValues == null || valueHandler != null ? new Text(choiceComposite, style) : null;
+    if (choiceText != null)
+    {
+      GridData choiceTextGridData = new GridData();
+      choiceTextGridData.widthHint = Display.getCurrent().getBounds().width / 5;
+      choiceTextGridData.verticalAlignment = SWT.BEGINNING;
+      choiceTextGridData.horizontalAlignment = SWT.FILL;
+      choiceTextGridData.grabExcessHorizontalSpace = true;
+      if (multiLine)
+      {
+        choiceTextGridData.verticalAlignment = SWT.FILL;
+        choiceTextGridData.grabExcessVerticalSpace = true;
+      }
+      choiceText.setLayoutData(choiceTextGridData);
+      if (valueHandler == null)
+      {
+        valueHandler = new ItemPropertyDescriptor.DataTypeValueHandler((EDataType)eClassifier);
+      }
+    }
+
     final Table choiceTable = choiceOfValues == null ? null : new Table(choiceComposite, SWT.MULTI | SWT.BORDER);
     if (choiceTable != null)
     {
@@ -278,7 +338,6 @@
         choiceTableViewer.addFilter
           (new ViewerFilter()
            {
-             
              @Override
              public boolean select(Viewer viewer, Object parentElement, Object element)
              {
@@ -289,27 +348,6 @@
       choiceTableViewer.setInput(new ItemProvider(choiceOfValues));
     }
 
-    // We use multi even for a single line because we want to respond to the enter key.
-    //
-    int style = multiLine ?
-      SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER :
-      SWT.MULTI | SWT.BORDER;
-    final Text choiceText = choiceOfValues == null ? new Text(choiceComposite, style) : null;
-    if (choiceText != null)
-    {
-      GridData choiceTextGridData = new GridData();
-      choiceTextGridData.widthHint = Display.getCurrent().getBounds().width / 5;
-      choiceTextGridData.verticalAlignment = SWT.BEGINNING;
-      choiceTextGridData.horizontalAlignment = SWT.FILL;
-      choiceTextGridData.grabExcessHorizontalSpace = true;
-      if (multiLine)
-      {
-        choiceTextGridData.verticalAlignment = SWT.FILL;
-        choiceTextGridData.grabExcessVerticalSpace = true;
-      }
-      choiceText.setLayoutData(choiceTextGridData);
-    }
-
     Composite controlButtons = new Composite(contents, SWT.NONE);
     GridData controlButtonsGridData = new GridData();
     controlButtonsGridData.verticalAlignment = SWT.FILL;
@@ -320,13 +358,17 @@
     controlButtons.setLayout(controlsButtonGridLayout);
 
     new Label(controlButtons, SWT.NONE);
-    
+
     final Button addButton = new Button(controlButtons, SWT.PUSH);
     addButton.setText(EMFEditUIPlugin.INSTANCE.getString("_UI_Add_label"));
     GridData addButtonGridData = new GridData();
     addButtonGridData.verticalAlignment = SWT.FILL;
     addButtonGridData.horizontalAlignment = SWT.FILL;
     addButton.setLayoutData(addButtonGridData);
+    if (valueHandler != null)
+    {
+      addButton.setEnabled(valueHandler.isValid("") == null);
+    }
 
     final Button removeButton = new Button(controlButtons, SWT.PUSH);
     removeButton.setText(EMFEditUIPlugin.INSTANCE.getString("_UI_Remove_label"));
@@ -334,12 +376,12 @@
     removeButtonGridData.verticalAlignment = SWT.FILL;
     removeButtonGridData.horizontalAlignment = SWT.FILL;
     removeButton.setLayoutData(removeButtonGridData);
-    
+
     Label spaceLabel = new Label(controlButtons, SWT.NONE);
     GridData spaceLabelGridData = new GridData();
     spaceLabelGridData.verticalSpan = 2;
     spaceLabel.setLayoutData(spaceLabelGridData);
-    
+
     final Button upButton = new Button(controlButtons, SWT.PUSH);
     upButton.setText(EMFEditUIPlugin.INSTANCE.getString("_UI_Up_label"));
     GridData upButtonGridData = new GridData();
@@ -375,7 +417,7 @@
     featureLabelGridData.horizontalAlignment = SWT.FILL;
     featureLabelGridData.verticalAlignment = SWT.FILL;
     featureLabel.setLayoutData(featureLabelGridData);
-    
+
     final Table featureTable = new Table(featureComposite, SWT.MULTI | SWT.BORDER);
     GridData featureTableGridData = new GridData();
     featureTableGridData.widthHint = Display.getCurrent().getBounds().width / 5;
@@ -386,18 +428,110 @@
     featureTableGridData.grabExcessVerticalSpace= true;
     featureTable.setLayoutData(featureTableGridData);
 
-    final TableViewer featureTableViewer = new TableViewer(featureTable);
+    // We carefully manage the selection because for non-unique features,
+    // because the value selected by a selection-preserving refresh will be the first of the duplicates.
+    //
+    final TableViewer featureTableViewer = new TableViewer(featureTable)
+      {
+        @Override
+        public void refresh(Object element, boolean updateLabels)
+        {
+          internalRefresh(element, updateLabels);
+        }
+
+        @Override
+        public void refresh(Object element)
+        {
+          internalRefresh(element);
+        }
+      };
     featureTableViewer.setContentProvider(contentProvider);
     featureTableViewer.setLabelProvider(labelProvider);
     featureTableViewer.setInput(values);
+
+    featureTableViewer.addSelectionChangedListener(new ISelectionChangedListener()
+      {
+        public void selectionChanged(SelectionChangedEvent event)
+        {
+          // Remove is enabled only if something is selected.
+          //
+          removeButton.setEnabled(!event.getSelection().isEmpty());
+
+          int[] selectionIndices = getSelectionIndices(featureTable);
+
+          // Up is enabled only if something will actually be moved up.
+          //
+          boolean upEnabled = false;
+          int upIndex = Math.max(selectionIndices[0] - 1, 0);
+          for (int i = 0; i < selectionIndices.length; ++i)
+          {
+            if (upIndex++ != selectionIndices[i])
+            {
+              upEnabled = true;
+            }
+          }
+          upButton.setEnabled(upEnabled);
+
+          // Down is enabled only if something will actually be moved up.
+          //
+          boolean downEnabled = false;
+          int downIndex = Math.min(selectionIndices[selectionIndices.length - 1] + 1, featureTable.getItemCount() - 1);
+          for (int i = selectionIndices.length - 1; i >= 0; --i)
+          {
+            if (downIndex-- !=  selectionIndices[i])
+            {
+              downEnabled = true;
+            }
+          }
+          downButton.setEnabled(downEnabled);
+        }
+      });
+
+    // Manage the active control used by the Add button.
+    //
+    class ActiveControl
+    {
+      private Control control = choiceText == null ? choiceTable : choiceText;
+
+      public Control get()
+      {
+        return control;
+      }
+
+      public void set(Control control)
+      {
+        this.control = control;
+        if (control == choiceText)
+        {
+          choiceText.notifyListeners(SWT.Modify, null);
+        }
+        else
+        {
+          choiceTable.notifyListeners(SWT.Selection, null);
+          setErrorMessage(null);
+        }
+      }
+    }
+    final ActiveControl activeControl = new ActiveControl();
+
     final EList<Object> children = values.getChildren();
     if (!children.isEmpty())
     {
       featureTableViewer.setSelection(new StructuredSelection(children.get(0)));
     }
-    
+
     if (choiceTableViewer != null)
     {
+      choiceTableViewer.addSelectionChangedListener(new ISelectionChangedListener()
+        {
+          public void selectionChanged(SelectionChangedEvent event)
+          {
+            if (activeControl.get() == choiceTable)
+            {
+              addButton.setEnabled(!event.getSelection().isEmpty());
+            }
+          }
+        });
       choiceTableViewer.addDoubleClickListener(new IDoubleClickListener()
         {
           public void doubleClick(DoubleClickEvent event)
@@ -408,19 +542,27 @@
             }
           }
         });
-
-      featureTableViewer.addDoubleClickListener(new IDoubleClickListener()
-      {
-        public void doubleClick(DoubleClickEvent event)
+      choiceTable.addFocusListener(new FocusAdapter()
         {
-          if (removeButton.isEnabled())
+          @Override
+          public void focusGained(FocusEvent e)
           {
-            removeButton.notifyListeners(SWT.Selection, null);
+            activeControl.set(choiceTable);
           }
-        }
-      });
+        });
     }
-    
+
+    featureTableViewer.addDoubleClickListener(new IDoubleClickListener()
+    {
+      public void doubleClick(DoubleClickEvent event)
+      {
+        if (removeButton.isEnabled())
+        {
+          removeButton.notifyListeners(SWT.Selection, null);
+        }
+      }
+    });
+
     if (choiceText != null)
     {
       choiceText.addKeyListener(
@@ -431,43 +573,62 @@
           {
             if (!multiLine && (event.character == '\r' || event.character == '\n'))
             {
-              try
-              {
-                Object value = EcoreUtil.createFromString((EDataType)eClassifier, choiceText.getText());
-                children.add(value);
-                choiceText.setText("");
-                featureTableViewer.refresh();
-                featureTableViewer.setSelection(new StructuredSelection(value));
-                event.doit = false;
-              }
-              catch (RuntimeException exception)
-              {
-                // Ignore
-              }
-            }
-            else if (event.character == '\33')
-            {
-              choiceText.setText("");
               event.doit = false;
+              if (addButton.isEnabled())
+              {
+                addButton.notifyListeners(SWT.Selection, null);
+              }
             }
           }
         });
+      choiceText.addModifyListener(
+        new ModifyListener()
+        {
+          public void modifyText(ModifyEvent e)
+          {
+            if (activeControl.get() == choiceText)
+            {
+              String errorMessage = valueHandler.isValid(choiceText.getText());
+              if (errorMessage == null && unique && children.contains(valueHandler.toValue(choiceText.getText())))
+              {
+                errorMessage = EMFEditUIPlugin.INSTANCE.getString("_UI_DuplicateValue_message");
+              }
+              setErrorMessage(errorMessage);
+              addButton.setEnabled(errorMessage == null);
+            }
+          }
+        });
+      choiceText.addFocusListener(new FocusAdapter()
+        {
+          @Override
+          public void focusGained(FocusEvent e)
+          {
+            activeControl.set(choiceText);
+          }
+        });
     }
-        
+
     upButton.addSelectionListener(
       new SelectionAdapter()
       {
         @Override
         public void widgetSelected(SelectionEvent event)
         {
-          IStructuredSelection selection = (IStructuredSelection)featureTableViewer.getSelection();
-          int minIndex = 0;
-          for (Iterator<?> i = selection.iterator(); i.hasNext();)
+          // We use indices to properly handle non-unique values.
+          //
+          int[] selectionIndices = getSelectionIndices(featureTable);
+          int index = Math.max(selectionIndices[0] - 1, 0);
+          int start = index;
+          for (int i = 0; i < selectionIndices.length; ++i)
           {
-            Object value = i.next();
-            int index = children.indexOf(value);
-            children.move(Math.max(index - 1, minIndex++), value);
+            children.move(index++, selectionIndices[i]);
           }
+
+          // We manage the selection to select exactly the appropriate indices.
+          //
+          featureTableViewer.refresh();
+          featureTable.setSelection(start, start + selectionIndices.length - 1);
+          featureTable.notifyListeners(SWT.Selection, null);
         }
       });
 
@@ -477,56 +638,105 @@
         @Override
         public void widgetSelected(SelectionEvent event)
         {
-          IStructuredSelection selection = (IStructuredSelection)featureTableViewer.getSelection();
-          int maxIndex = children.size() - 1;
-          List<?> objects = selection.toList();
-          for (ListIterator<?> i = objects.listIterator(objects.size()); i.hasPrevious();)
+          // We use indices to properly handle non-unique values.
+          //
+          int[] selectionIndices = getSelectionIndices(featureTable);
+          int index = Math.min(selectionIndices[selectionIndices.length - 1] + 1, children.size() - 1);
+          for (int i = selectionIndices.length - 1; i >= 0; --i)
           {
-            Object value = i.previous();
-            int index = children.indexOf(value);
-            children.move(Math.min(index + 1, maxIndex--), value);
+            children.move(index--, selectionIndices[i]);
           }
+
+          // We manage the selection to select exactly the appropriate indices.
+          //
+          featureTableViewer.refresh();
+          featureTable.setSelection(index + 1, index + selectionIndices.length);
+          featureTable.notifyListeners(SWT.Selection, null);
         }
       });
 
     addButton.addSelectionListener(
       new SelectionAdapter()
       {
-        // event is null when choiceTableViewer is double clicked
         @Override
         public void widgetSelected(SelectionEvent event)
         {
-          if (choiceTableViewer != null)
+          // If there is a choice table and there is no choice text or the choice table is the active control...
+          //
+          if (choiceTableViewer != null && (choiceText == null || activeControl.get() == choiceTable))
           {
+            // Remember the selection of the choices table.
+            //
+            int[] selectionIndices = getSelectionIndices(choiceTable);
+
+            // Process the selected values...
+            //
             IStructuredSelection selection = (IStructuredSelection)choiceTableViewer.getSelection();
-            for (Iterator<?> i = selection.iterator(); i.hasNext();)
+            int addCount = 0;
+            for (Object value : selection.toArray())
             {
-              Object value = i.next();
+              // If duplicates are allowed or the value isn't already present...
+              //
               if (!unique || !children.contains(value))
               {
+                // Add the value and remember how many we added.
                 children.add(value);
+                ++addCount;
+
+                // If there is a choice text, and its value is equal to the text value we added, clear that value.
+                //
+                if (choiceText != null && choiceText.getText().equals(valueHandler.toString(value)))
+                {
+                  choiceText.setText("");
+                }
               }
             }
+
+            // Select exactly the expected indices.
+            //
             featureTableViewer.refresh();
-            featureTableViewer.setSelection(selection);
+            featureTable.setSelection(children.size() - addCount, children.size() - 1);
+            featureTable.notifyListeners(SWT.Selection, null);
+
+            // Refresh the choice table based on the filters and if the table isn't empty and there is no selection.
+            //
             choiceTableViewer.refresh();
+            if (choiceTable.getItemCount() > 0 && getSelectionIndices(choiceTable).length == 0)
+            {
+              // Select the index before the previously selected index.
+              //
+              choiceTable.setSelection(selectionIndices.length == 0 || selectionIndices[0] == 0 ? 0 : selectionIndices[0] - 1);
+              choiceTableViewer.setSelection(choiceTableViewer.getSelection());
+            }
           }
           else if (choiceText != null)
           {
-            try
+            // Convert the value, add it, and clear the value from the choice text.
+            //
+            Object value = valueHandler.toValue(choiceText.getText());
+            children.add(value);
+            choiceText.setText("");
+
+            // Select the new value at the end of the table.
+            //
+            featureTableViewer.refresh();
+            featureTable.setSelection(featureTable.getItemCount() - 1);
+            featureTable.notifyListeners(SWT.Selection, null);
+
+            // If there is a choice table...
+            //
+            if (choiceTableViewer != null)
             {
-              Object value = EcoreUtil.createFromString((EDataType)eClassifier, choiceText.getText());
-              if (!unique || !children.contains(value))
+              // Refresh it and if there is no longer a selection and the table isn't empty...
+              //
+              choiceTableViewer.refresh();
+              if (choiceTableViewer.getSelection().isEmpty() && choiceTable.getItemCount() > 0)
               {
-                children.add(value);
-                choiceText.setText("");
+                // Select the first item in the table.
+                //
+                choiceTable.setSelection(0);
+                choiceTable.notifyListeners(SWT.Selection, null);
               }
-              featureTableViewer.refresh();
-              featureTableViewer.setSelection(new StructuredSelection(value));
-            }
-            catch (RuntimeException exception)
-            {
-              // Ignore
             }
           }
         }
@@ -535,47 +745,140 @@
     removeButton.addSelectionListener(
       new SelectionAdapter()
       {
-        // event is null when featureTableViewer is double clicked 
         @Override
         public void widgetSelected(SelectionEvent event)
         {
+          // Remember the selection in the feature table...
+          //
           IStructuredSelection selection = (IStructuredSelection)featureTableViewer.getSelection();
-          Object firstValue = null;
-          for (Iterator<?> i = selection.iterator(); i.hasNext();)
+
+          // Process the selection to remove the appropriate values.
+          // And remember the value we might put into the choice text.
+          //
+          int[] selectionIndices = getSelectionIndices(featureTable);
+          Object firstValue = children.get(selectionIndices[0]);
+          for (int i = selectionIndices.length -1; i >= 0; --i)
           {
-            Object value = i.next();
-            if (firstValue == null)
-            {
-              firstValue = value;
-            }
-            children.remove(value);
+            children.remove(selectionIndices[i]);
           }
 
+          // Refresh the feature table and select the index before the previous selection.
+          //
+          featureTableViewer.refresh();
           if (!children.isEmpty())
           {
-            featureTableViewer.setSelection(new StructuredSelection(children.get(0)));
+            featureTable.setSelection(selectionIndices[0] == 0 ? 0 : selectionIndices[0] - 1);
+            featureTable.notifyListeners(SWT.Selection, null);
           }
 
+          // If there is a choice table...
+          //
           if (choiceTableViewer != null)
           {
+            // Refresh it and select the values we just removed.
+            //
             choiceTableViewer.refresh();
             choiceTableViewer.setSelection(selection);
-          }
-          else if (choiceText != null)
-          {
-            if (firstValue != null)
+
+            // Check which values are actually selected, them from the list of things we tried to select...
+            //
+            IStructuredSelection choiceSelection = (IStructuredSelection)choiceTableViewer.getSelection();
+            @SuppressWarnings("unchecked")
+            List<?> values = new ArrayList<Object>(selection.toList());
+            values.removeAll(choiceSelection.toList());
+
+            // If there is a value that was removed but isn't selected in the choice table...
+            //
+            if (!values.isEmpty())
             {
-              String value = EcoreUtil.convertToString((EDataType)eClassifier, firstValue);
-              choiceText.setText(value);
+              // Use the first such value as the value to set into the choice text.
+              //
+              firstValue = values.get(0);
+            }
+          }
+
+          // If there is a choice text, and we have a value...
+          //
+          if (choiceText != null && firstValue != null)
+          {
+            // Convert the value to text, and set it into the choice.
+            //
+            String value = valueHandler.toString(firstValue);
+            choiceText.setText(value);
+
+            // If the choice table is the active control and it doesn't have a selection...
+            //
+            if (activeControl.get() == choiceTable && choiceTableViewer.getSelection().isEmpty())
+            {
+              // Make the choice text the active control.
+              // This ensures that when you do a remove, that the Add button is enabled and you can add the value back.
+              //
+              activeControl.set(choiceText);
             }
           }
         }
-      });    
-        
+      });
+
+    // If there is a choice text, clear the error message to ensure that the dialog does not come up initially in an error state.
+    // The add button will be disabled if there is an error message.
+    //
+    if (choiceText != null)
+    {
+      choiceText.getDisplay().asyncExec(new Runnable()
+        {
+          public void run()
+          {
+            if (!choiceText.isDisposed())
+            {
+              if (choiceTable != null && choiceTable.getItemCount() == 0)
+              {
+                choiceText.setFocus();
+              }
+              setErrorMessage(null);
+            }
+          }
+        });
+    }
+
     return contents;
   }
 
   @Override
+  protected Control createButtonBar(Composite parent)
+  {
+    // Specialize the button area so that we can provide a label control that displays error messages.
+    //
+    Composite composite = new Composite(parent, SWT.NONE);
+    GridLayout layout = new GridLayout();
+    layout.numColumns = 2;
+    composite.setLayout(layout);
+    GridData data = new GridData(GridData.HORIZONTAL_ALIGN_FILL | GridData.VERTICAL_ALIGN_CENTER);
+    composite.setLayoutData(data);
+    composite.setFont(parent.getFont());
+
+    Label label = new Label(composite, SWT.NONE);
+    label.setForeground(JFaceColors.getErrorText(label.getDisplay()));
+    GridData labelData = new GridData(GridData.HORIZONTAL_ALIGN_FILL | GridData.VERTICAL_ALIGN_CENTER | GridData.GRAB_HORIZONTAL);
+    labelData.horizontalIndent = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_MARGIN);
+    label.setLayoutData(labelData);
+
+    Control buttonBar = super.createButtonBar(composite);
+    GridData buttonBarData = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING | GridData.VERTICAL_ALIGN_CENTER);
+    buttonBar.setLayoutData(buttonBarData);
+    return buttonBar;
+  }
+
+  /**
+   * @since 2.14
+   */
+  protected void setErrorMessage(String message)
+  {
+    Label label = (Label)getButtonBar().getParent().getChildren()[0];
+    label.setText(message == null ? "" : message);
+    label.setToolTipText(message == null ? "" : message);
+  }
+
+  @Override
   protected void okPressed()
   {
     result = new BasicEList<Object>(values.getChildren());
@@ -593,4 +896,11 @@
   {
     return result;
   }
+
+  private static int[] getSelectionIndices(Table table)
+  {
+    int[] selectionIndices = table.getSelectionIndices();
+    Arrays.sort(selectionIndices);
+    return selectionIndices;
+  }
 }
diff --git a/plugins/org.eclipse.emf.edit.ui/src/org/eclipse/emf/edit/ui/provider/DiagnosticDecorator.java b/plugins/org.eclipse.emf.edit.ui/src/org/eclipse/emf/edit/ui/provider/DiagnosticDecorator.java
index ffc7f2f..60c3bb4 100644
--- a/plugins/org.eclipse.emf.edit.ui/src/org/eclipse/emf/edit/ui/provider/DiagnosticDecorator.java
+++ b/plugins/org.eclipse.emf.edit.ui/src/org/eclipse/emf/edit/ui/provider/DiagnosticDecorator.java
@@ -119,6 +119,11 @@
             escape = true;
             break;
           }
+          case ' ':
+          {
+            result.append("&#160;");
+            break;
+          }
           case '&':
           {
             result.append("&amp;");
@@ -479,7 +484,7 @@
                       }
                       else
                       {
-                        return escapeContent(text);
+                        return text;
                       }
                     }
 
@@ -657,6 +662,10 @@
               }
             }
           });
+
+        // If the job was only scheduled and not yet running, it will not get a chance to clear its field.
+        // So best we do it here to be sure it's done and a new job can be created and scheduled.
+        this.validationJob = null;
       }
     }
 
@@ -1515,6 +1524,18 @@
       for (Object object : propertySheetPage.getInput())
       {
         decorate(decorations, object, objects.get(object), null);
+        if (object instanceof EObject)
+        {
+          EObject eObject = (EObject)object;
+          for (EObject child : eObject.eContents())
+          {
+            decorate(decorations, child, objects.get(child), null);
+          }
+          for (EObject child : eObject.eCrossReferences())
+          {
+            decorate(decorations, child, objects.get(child), null);
+          }
+        }
       }
     }
     else
@@ -1684,7 +1705,7 @@
       ExtendedImageRegistry.INSTANCE.getImageDescriptor
         (EMFEditUIPlugin.INSTANCE.getImage(diagnostic.getSeverity() == Diagnostic.WARNING ? "full/ovr16/warning_ovr.gif" : "full/ovr16/error_ovr.gif"));
     URI severityURI = ImageURIRegistry.INSTANCE.getImageURI(imageDescriptor);
-    result.append("<div>");
+    result.append("<div style='white-space: nowrap;'>");
     for (int i = 0; i < indentation; ++i)
     {
       result.append("&#160;&#160;&#160;");
@@ -1702,7 +1723,7 @@
         EObject eObject = (EObject)data;
         if (eObject.eResource() != null && eObject.eResource().getResourceSet() == resourceSet)
         {
-          result.append("<div>");
+          result.append("<div style='white-space: nowrap;'>");
           for (int i = 0; i <= indentation; ++i)
           {
             result.append("&#160;&#160;&#160;");
@@ -1739,6 +1760,7 @@
       ++index;
       if (data.size() > 1)
       {
+        result.append("<div style='white-space: nowrap;'>");
         result.append("<div>");
         Image image = labelProvider.getImage(object);
         if (image != null)
diff --git a/plugins/org.eclipse.emf.edit.ui/src/org/eclipse/emf/edit/ui/provider/PropertyDescriptor.java b/plugins/org.eclipse.emf.edit.ui/src/org/eclipse/emf/edit/ui/provider/PropertyDescriptor.java
index 38bc11a..67ecbb1 100644
--- a/plugins/org.eclipse.emf.edit.ui/src/org/eclipse/emf/edit/ui/provider/PropertyDescriptor.java
+++ b/plugins/org.eclipse.emf.edit.ui/src/org/eclipse/emf/edit/ui/provider/PropertyDescriptor.java
@@ -11,41 +11,60 @@
 package org.eclipse.emf.edit.ui.provider;
 
 
+import java.text.MessageFormat;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collection;
 import java.util.List;
+import java.util.Locale;
 
 import org.eclipse.jface.dialogs.IDialogConstants;
 import org.eclipse.jface.dialogs.IInputValidator;
 import org.eclipse.jface.viewers.CellEditor;
+import org.eclipse.jface.viewers.CheckboxCellEditor;
 import org.eclipse.jface.viewers.ICellEditorValidator;
 import org.eclipse.jface.viewers.ILabelProvider;
 import org.eclipse.jface.viewers.LabelProvider;
 import org.eclipse.jface.viewers.TextCellEditor;
 import org.eclipse.jface.window.Window;
 import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.FocusAdapter;
+import org.eclipse.swt.events.FocusEvent;
+import org.eclipse.swt.events.KeyAdapter;
+import org.eclipse.swt.events.KeyEvent;
 import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.MouseAdapter;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.MouseListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.TraverseEvent;
+import org.eclipse.swt.events.TraverseListener;
+import org.eclipse.swt.events.VerifyEvent;
+import org.eclipse.swt.events.VerifyListener;
+import org.eclipse.swt.graphics.Color;
 import org.eclipse.swt.graphics.Image;
 import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.layout.RowLayout;
+import org.eclipse.swt.widgets.Button;
 import org.eclipse.swt.widgets.Composite;
 import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
 import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Table;
 import org.eclipse.swt.widgets.Text;
+import org.eclipse.swt.widgets.Tree;
 import org.eclipse.ui.views.properties.IPropertyDescriptor;
-
 import org.eclipse.emf.common.ui.celleditor.ExtendedComboBoxCellEditor;
 import org.eclipse.emf.common.ui.celleditor.ExtendedDialogCellEditor;
-import org.eclipse.emf.common.util.Diagnostic;
 import org.eclipse.emf.ecore.EClassifier;
 import org.eclipse.emf.ecore.EDataType;
 import org.eclipse.emf.ecore.EReference;
 import org.eclipse.emf.ecore.EStructuralFeature;
 import org.eclipse.emf.ecore.EcorePackage;
-import org.eclipse.emf.ecore.util.Diagnostician;
-import org.eclipse.emf.ecore.util.EcoreUtil;
 import org.eclipse.emf.edit.provider.IItemLabelProvider;
 import org.eclipse.emf.edit.provider.IItemPropertyDescriptor;
+import org.eclipse.emf.edit.provider.ItemPropertyDescriptor;
 import org.eclipse.emf.edit.ui.EMFEditUIPlugin;
 import org.eclipse.emf.edit.ui.celleditor.FeatureEditorDialog;
 
@@ -147,45 +166,42 @@
   /**
    * A delegate for handling validation and conversion for data type values.
    */
-  protected static class EDataTypeValueHandler implements ICellEditorValidator, IInputValidator
+  protected static class EDataTypeValueHandler implements ICellEditorValidator, IInputValidator, ExtendedComboBoxCellEditor.ValueHandler
   {
     protected EDataType eDataType;
 
+    /**
+     * @since 2.14
+     */
+    protected IItemPropertyDescriptor.ValueHandler valueHandler;
+
     public EDataTypeValueHandler(EDataType eDataType)
     {
+      this(eDataType, new ItemPropertyDescriptor.DataTypeValueHandler(eDataType));
+    }
+
+    /**
+     * @since 2.14
+     */
+    public EDataTypeValueHandler(EDataType eDataType, IItemPropertyDescriptor.ValueHandler valueHandler)
+    {
       this.eDataType = eDataType;
+      this.valueHandler = valueHandler;
     }
 
     public String isValid(Object object)
     {
-      Object value;
-      try
-      {
-        value = eDataType.getEPackage().getEFactoryInstance().createFromString(eDataType, (String)object);
-      }
-      catch (Exception exception)
-      {
-        String message = exception.getClass().getName();
-        int index = message.lastIndexOf('.');
-        if (index >= 0)
-        {
-          message = message.substring(index + 1);
-        }
-        if (exception.getLocalizedMessage() != null)
-        {
-          message = message + ": " + exception.getLocalizedMessage();
-        }
-        return message;
-      }
-      Diagnostic diagnostic = Diagnostician.INSTANCE.validate(eDataType, value);
-      if (diagnostic.getSeverity() == Diagnostic.OK)
-      {
-        return null;
-      }
-      else
-      {
-        return (diagnostic.getChildren().get(0)).getMessage().replaceAll("'","''").replaceAll("\\{", "'{'"); // }}
-      }
+      return escape(valueHandler.isValid((String)object));
+    }
+
+    /**
+     * JFace {@link MessageFormat#format(String, Object...) formats} messages, so special pattern characters need to be escaped.
+     * 
+     * @since 2.14
+     */
+    protected String escape(String message)
+    {
+      return message == null ? null : message.replaceAll("'","''").replaceAll("\\{", "'{'"); // }}
     }
 
     public String isValid(String text)
@@ -195,15 +211,14 @@
 
     public Object toValue(String string)
     {
-      return EcoreUtil.createFromString(eDataType, string);
+      return valueHandler.toValue(string);
     }
 
     public String toString(Object value)
     {
-      String result = EcoreUtil.convertToString(eDataType, value);
+      String result = valueHandler.toString(value);
       return result == null ? "" : result;
     }
-    
   }
 
   public static class EDataTypeCellEditor extends TextCellEditor
@@ -213,9 +228,17 @@
 
     public EDataTypeCellEditor(EDataType eDataType, Composite parent)
     {
+      this(eDataType, new EDataTypeValueHandler(eDataType), parent);
+    }
+
+    /**
+     * @since 2.14
+     */
+    public EDataTypeCellEditor(EDataType eDataType, EDataTypeValueHandler valueHandler, Composite parent)
+    {
       super(parent);
       this.eDataType = eDataType;
-      valueHandler = new EDataTypeValueHandler(eDataType);
+      this.valueHandler = valueHandler;
       setValidator(valueHandler);
     }
 
@@ -258,12 +281,450 @@
     }
   }
 
+  /**
+   * @since 2.14
+   */
+  public static class MultiLineEDataTypeCellEditor extends EDataTypeCellEditor
+  {
+    private static final EDataTypeValueHandler NO_OP_VALUE_HANDLER = new EDataTypeValueHandler(EcorePackage.Literals.ESTRING);
+
+    protected Text text;
+
+    protected Button button;
+
+    protected boolean doEscape;
+
+    private String value;
+
+    private String dialogTitle;
+
+    private MouseListener mouseListener = new MouseAdapter()
+      {
+        @Override
+        public void mouseUp(MouseEvent e)
+        {
+          showDialog();
+        }
+
+        @Override
+        public void mouseDoubleClick(MouseEvent e)
+        {
+          showDialog();
+        }
+      };
+
+    private VerifyListener verifyListener = new VerifyListener()
+      {
+        public void verifyText(VerifyEvent e)
+        {
+          e.doit = false;
+          showDialog();
+        }
+      };
+
+    public MultiLineEDataTypeCellEditor(EDataType eDataType, EDataTypeValueHandler valueHandler, String dialogTitle, Composite parent)
+    {
+      super(eDataType, valueHandler, parent);
+      this.dialogTitle = dialogTitle;
+    }
+
+    private void showDialog()
+    {
+      button.setFocus();
+      button.getDisplay().asyncExec(new Runnable()
+        {
+          public void run()
+          {
+            button.notifyListeners(SWT.Selection, null);
+          }
+        });
+    }
+
+    @Override
+    public Object doGetValue()
+    {
+      String str = value != null ? value : (String)super.doGetValue();
+
+      if (doEscape)
+      {
+        str = unescape(str);
+      }
+
+      return str;
+    }
+
+    @Override
+    public void doSetValue(Object value)
+    {
+      text.removeMouseListener(mouseListener);
+      text.removeVerifyListener(verifyListener);
+
+      String literal = valueHandler.toString(value);
+      if (literal != null)
+      {
+        for (char c : literal.toCharArray())
+        {
+          if (Character.isISOControl(c))
+          {
+            doEscape = true;
+            button.setImage(ExtendedImageRegistry.INSTANCE.getImage(EMFEditUIPlugin.INSTANCE.getImage("full/ctool16/EncodedEllipses")));
+            literal = escape(literal);
+            break;
+          }
+        }
+      }
+
+      EDataTypeValueHandler oldValueHandler = valueHandler;
+      try
+      {
+        boolean isVeryLong = literal.length() > 2000;
+        if (isVeryLong)
+        {
+          this.value = literal;
+          literal = literal.substring(0, 2000);
+        }
+        else
+        {
+          this.value = null;
+        }
+
+        valueHandler = NO_OP_VALUE_HANDLER;
+        super.doSetValue(literal);
+
+        if (isVeryLong)
+        {
+          text.addMouseListener(mouseListener);
+          text.addVerifyListener(verifyListener);
+        }
+      }
+      finally
+      {
+        valueHandler = oldValueHandler;
+      }
+    }
+
+    @Override
+    protected Control createControl(Composite parent)
+    {
+      GridLayout layout = new GridLayout(2, false);
+      layout.marginWidth = 0;
+      layout.marginHeight = 0;
+      layout.horizontalSpacing = 0;
+
+      final Composite composite = new Composite(parent, SWT.NONE);
+      composite.setLayout(layout);
+      composite.setFont(parent.getFont());
+      composite.setBackground(parent.getBackground());
+
+      text = (Text)super.createControl(composite);
+      text.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+
+      button = new Button(composite, SWT.PUSH);
+      GridData layoutData = new GridData(SWT.FILL, SWT.FILL, false, true);
+      if (parent instanceof Tree)
+      {
+        layoutData.widthHint = ((Tree)parent).getItemHeight();
+      }
+      else if (parent instanceof Table)
+      {
+       layoutData.widthHint = ((Table)parent).getItemHeight();
+      }
+      button.setLayoutData(layoutData);
+      button.setImage(ExtendedImageRegistry.INSTANCE.getImage(EMFEditUIPlugin.INSTANCE.getImage("full/ctool16/Ellipses")));
+      button.addSelectionListener(new SelectionAdapter()
+        {
+          @Override
+          public void widgetSelected(SelectionEvent e)
+          {
+            String stringValue = valueHandler.toString(getValue());
+            boolean containsNull = stringValue.indexOf('\u0000') != -1;
+            if (containsNull)
+            {
+              stringValue = stringValue.replace('\u0000', '\n');
+            }
+
+            MultiLineInputDialog dialog = new MultiLineInputDialog(
+              composite.getShell(),
+              dialogTitle,
+              EMFEditUIPlugin.INSTANCE.getString("_UI_MultiLineInputDialog_message"),
+              stringValue,
+              valueHandler);
+
+            if (dialog.open() == Window.OK)
+            {
+              String value = dialog.getValue();
+
+              value = value.replace("\r\n", "\n");
+              if (containsNull)
+              {
+                value = value.replace('\n', '\u0000');
+              }
+
+              Object newValue = valueHandler.toValue(value);
+              if (newValue != null)
+              {
+                boolean newValidState = isCorrect(newValue);
+                if (newValidState)
+                {
+                  markDirty();
+                  doSetValue(newValue);
+                  fireApplyEditorValue();
+                }
+              }
+            }
+            else
+            {
+              fireCancelEditor();
+            }
+          }
+        });
+
+      button.addKeyListener(new KeyAdapter()
+        {
+          @Override
+          public void keyReleased(KeyEvent e)
+          {
+            if (e.character == '\u001b')
+            {
+              fireCancelEditor();
+            }
+          }
+        });
+
+      return composite;
+    }
+
+    @Override
+    protected void focusLost()
+    {
+      if (isActivated())
+      {
+        button.getDisplay().asyncExec(new Runnable()
+          {
+            public void run()
+            {
+              try
+              {
+                if (button.isFocusControl())
+                {
+                  return;
+                }
+              }
+              catch (Exception ex)
+              {
+                // Ignore.
+              }
+
+              try
+              {
+                fireApplyEditorValue();
+                deactivate();
+              }
+              catch (Exception ex)
+              {
+                // Ignore.
+              }
+            }
+          });
+      }
+    }
+
+    protected String escape(String literal)
+    {
+      if (literal == null)
+      {
+        return null;
+      }
+
+      int len = literal.length();
+      StringBuilder builder = new StringBuilder(len);
+
+      for (int i = 0; i < len; i++)
+      {
+        char c = literal.charAt(i);
+        if (c < 32)
+        {
+          switch (c)
+          {
+            case '\r':
+              builder.append('\\');
+              builder.append('r');
+              break;
+
+            case '\n':
+              builder.append('\\');
+              builder.append('n');
+              break;
+
+            case '\t':
+              builder.append('\\');
+              builder.append('t');
+              break;
+
+            case '\f':
+              builder.append('\\');
+              builder.append('f');
+              break;
+
+            case '\b':
+              builder.append('\\');
+              builder.append('b');
+              break;
+
+            default:
+              if (c > 0xf)
+              {
+                builder.append("\\u00" + charToHex(c));
+              }
+              else
+              {
+                builder.append("\\u000" + charToHex(c));
+              }
+          }
+        }
+        else if (c == '\\')
+        {
+          builder.append('\\');
+          builder.append('\\');
+        }
+        else
+        {
+          builder.append(c);
+        }
+      }
+
+      return builder.toString();
+    }
+
+    protected String unescape(String literal)
+    {
+      if (literal == null)
+      {
+        return null;
+      }
+
+      int len = literal.length();
+      StringBuilder builder = new StringBuilder(len);
+
+      StringBuilder unicodeBuilder = new StringBuilder(4);
+      boolean unicode = false;
+      boolean slash = false;
+
+      for (int i = 0; i < len; i++)
+      {
+        char c = literal.charAt(i);
+        if (unicode)
+        {
+          unicodeBuilder.append(c);
+          if (unicodeBuilder.length() == 4)
+          {
+            try
+            {
+              char value = hexToChar(unicodeBuilder.toString());
+              builder.append(value);
+              unicodeBuilder.setLength(0);
+              unicode = false;
+              slash = false;
+            }
+            catch (NumberFormatException ex)
+            {
+              builder.append('\\');
+              builder.append('u');
+              builder.append(unicodeBuilder);
+            }
+          }
+
+          continue;
+        }
+
+        if (slash)
+        {
+          slash = false;
+
+          switch (c)
+          {
+            case '\\':
+              builder.append('\\');
+              break;
+
+            case 'r':
+              builder.append('\r');
+              break;
+
+            case 'n':
+              builder.append('\n');
+              break;
+
+            case 't':
+              builder.append('\t');
+              break;
+
+            case 'f':
+              builder.append('\f');
+              break;
+
+            case 'b':
+              builder.append('\b');
+              break;
+
+            case 'u':
+              unicode = true;
+              break;
+
+            case '0':
+            case '1':
+            case '2':
+            case '3':
+              if (i + 2 < len && literal.charAt(i + 1) >= '0' && literal.charAt(i + 1) <= '7' && literal.charAt(i + 2) >= '0' && literal.charAt(i + 2) <= '7')
+              {
+                builder.append((char)Integer.parseInt(literal.substring(i, i + 3), 8));
+                i += 2;
+                continue;
+              }
+
+              //$FALL-THROUGH$
+            default:
+            {
+              builder.append(c);
+            }
+          }
+
+          continue;
+        }
+        else if (c == '\\')
+        {
+          slash = true;
+          continue;
+        }
+
+        builder.append(c);
+      }
+
+      if (slash)
+      {
+        builder.append('\\');
+      }
+
+      return builder.toString();
+    }
+
+    protected String charToHex(char ch)
+    {
+      return Integer.toHexString(ch).toUpperCase(Locale.ENGLISH);
+    }
+
+    protected char hexToChar(String s)
+    {
+      return (char)Integer.parseInt(s, 16);
+    }
+  }
+
   private static class MultiLineInputDialog extends InputDialog
   {
     public MultiLineInputDialog(Shell parentShell, String title, String message, String initialValue, IInputValidator validator)
     {
       super(parentShell, title, message, initialValue, validator);
-      setShellStyle(getShellStyle() | SWT.RESIZE);
+      setShellStyle(getShellStyle() | SWT.RESIZE | SWT.MAX);
     }
 
     @Override
@@ -278,29 +739,160 @@
     }
   }
 
-  protected CellEditor createEDataTypeCellEditor(final EDataType eDataType, Composite composite)
+  /**
+   * Unlike {@link CheckboxCellEditor} this really creates a check box.
+   *
+   * @since 2.14
+   */
+  public static class CheckBoxCellEditor extends CellEditor
+  {
+    private Button checkButton;
+
+    private boolean isTriState;
+
+    private Label label;
+
+    public CheckBoxCellEditor(Composite parent, int style, boolean isTriState)
+    {
+      super(parent, style);
+      this.isTriState = isTriState;
+    }
+
+    @Override
+    protected Control createControl(Composite parent)
+    {
+      Composite composite = new Composite(parent, SWT.NONE);
+      RowLayout layout = new RowLayout();
+      layout.marginTop = 1;
+      layout.marginBottom = 0;
+      layout.marginLeft = 5;
+      layout.center = true;
+      composite.setLayout(layout);
+      checkButton = new Button(composite, SWT.CHECK | getStyle());
+      checkButton.addFocusListener(new FocusAdapter()
+        {
+          @Override
+          public void focusLost(FocusEvent e)
+          {
+            CheckBoxCellEditor.this.focusLost();
+          }
+        });
+      checkButton.addSelectionListener(new SelectionAdapter()
+        {
+          @Override
+          public void widgetSelected(SelectionEvent e)
+          {
+            changeState(false);
+          }
+        });
+      checkButton.addTraverseListener(new TraverseListener()
+        {
+          public void keyTraversed(TraverseEvent e)
+          {
+            if (e.detail == SWT.TRAVERSE_ESCAPE)
+            {
+              fireCancelEditor();
+            }
+            else if (e.detail == SWT.TRAVERSE_RETURN)
+            {
+              focusLost();
+            }
+          }
+        });
+
+      label = new Label(composite, SWT.NONE);
+
+      MouseAdapter mouseListener = new MouseAdapter()
+        {
+          @Override
+          public void mouseUp(MouseEvent e)
+          {
+            changeState(true);
+          }
+        };
+
+      label.addMouseListener(mouseListener);
+      composite.addMouseListener(mouseListener);
+      Color background = parent.getBackground();
+      label.setBackground(background);
+      composite.setBackground(background);
+      return composite;
+    }
+
+    private void changeState(boolean toggle)
+    {
+      markDirty();
+      if (isTriState)
+      {
+        if (checkButton.getGrayed())
+        {
+          checkButton.setGrayed(false);
+          checkButton.setSelection(false);
+        }
+        else if (checkButton.getSelection() == toggle)
+        {
+          checkButton.setSelection(false);
+          checkButton.setGrayed(true);
+        }
+        else
+        {
+          checkButton.setSelection(true);
+        }
+      }
+      else if (toggle)
+      {
+        checkButton.setSelection(!checkButton.getSelection());
+      }
+      doSetValue(doGetValue());
+    }
+
+    @Override
+    protected Object doGetValue()
+    {
+      return checkButton.getGrayed() ? null : checkButton.getSelection();
+    }
+
+    @Override
+    protected void doSetValue(Object value)
+    {
+      checkButton.setSelection(Boolean.TRUE.equals(value));
+      checkButton.setGrayed(value == null);
+      label.setText(value == null ? "null" : Boolean.TRUE.equals(value) ? "true" : "false");
+      label.setEnabled(value != null);
+      label.getParent().layout();
+    }
+
+    @Override
+    protected void doSetFocus()
+    {
+      if (checkButton != null)
+      {
+        checkButton.setFocus();
+      }
+    }
+  }
+
+  /**
+   * @since 2.14
+   */
+  protected CellEditor createEDataTypeCellEditor(final EDataType eDataType, final IItemPropertyDescriptor.ValueHandler specializedValueHandler, Composite composite)
   {
     if (itemPropertyDescriptor.isMultiLine(object))
     {
-      return new ExtendedDialogCellEditor(composite, getEditLabelProvider())
-      {
-        protected EDataTypeValueHandler valueHandler = new EDataTypeValueHandler(eDataType);
-
-        @Override
-        protected Object openDialogBox(Control cellEditorWindow)
-        {
-          InputDialog dialog = new MultiLineInputDialog
-            (cellEditorWindow.getShell(),
-             EMFEditUIPlugin.INSTANCE.getString
-               ("_UI_FeatureEditorDialog_title", new Object [] { getDisplayName(), getEditLabelProvider().getText(object) }),
-             EMFEditUIPlugin.INSTANCE.getString("_UI_MultiLineInputDialog_message"),
-             valueHandler.toString(getValue()),
-             valueHandler);
-          return dialog.open() == Window.OK ? valueHandler.toValue(dialog.getValue()) : null;
-        }
-      };
+      EDataTypeValueHandler valueHandler = new EDataTypeValueHandler(eDataType, specializedValueHandler);
+      return new MultiLineEDataTypeCellEditor(
+        eDataType,
+        valueHandler,
+        EMFEditUIPlugin.INSTANCE.getString("_UI_FeatureEditorDialog_title", new Object []{ getDisplayName(), getEditLabelProvider().getText(object) }),
+        composite);
     }
-    return new EDataTypeCellEditor(eDataType, composite);
+    return specializedValueHandler == null
+      ? new EDataTypeCellEditor(eDataType, composite) : new EDataTypeCellEditor(eDataType, new EDataTypeValueHandler(eDataType, specializedValueHandler), composite);
+  }
+
+  protected CellEditor createEDataTypeCellEditor(final EDataType eDataType, Composite composite)
+  {
+    return createEDataTypeCellEditor(eDataType, null, composite);
   }
 
   /**
@@ -423,7 +1015,10 @@
         composite,
         new ArrayList<Object>(itemPropertyDescriptor.getChoiceOfValues(object)),
         getEditLabelProvider(),
-        itemPropertyDescriptor.isSortChoices(object));
+        itemPropertyDescriptor.isSortChoices(object),
+        SWT.READ_ONLY,
+        null,
+        true);
     }
     else if (genericFeature instanceof EStructuralFeature)
     {
@@ -463,7 +1058,11 @@
                     new ArrayList<Object>(choiceOfValues),
                     false,
                     itemPropertyDescriptor.isSortChoices(object),
-                    feature.isUnique() || feature instanceof EReference);
+                    feature.isUnique() || feature instanceof EReference,
+                    itemPropertyDescriptor instanceof IItemPropertyDescriptor.ValueHandlerProvider &&
+                      ((IItemPropertyDescriptor.ValueHandlerProvider)itemPropertyDescriptor).isChoiceArbitrary(object) ?
+                        ((IItemPropertyDescriptor.ValueHandlerProvider)itemPropertyDescriptor).getValueHandler(object) :
+                        null);
                   dialog.open();
                   return dialog.getResult();
                 }
@@ -473,20 +1072,37 @@
 
         if (result == null)
         {
-          result = 
-            new ExtendedComboBoxCellEditor
-              (composite, new ArrayList<Object>(choiceOfValues), getEditLabelProvider(), itemPropertyDescriptor.isSortChoices(object));
+          ArrayList<Object> values = new ArrayList<Object>(choiceOfValues);
+          if (itemPropertyDescriptor instanceof IItemPropertyDescriptor.ValueHandlerProvider &&
+                ((IItemPropertyDescriptor.ValueHandlerProvider)itemPropertyDescriptor).isChoiceArbitrary(object))
+          {
+            result =
+              new ExtendedComboBoxCellEditor
+                (composite,
+                 values,
+                 getEditLabelProvider(),
+                 itemPropertyDescriptor.isSortChoices(object),
+                 SWT.NONE,
+                 new EDataTypeValueHandler((EDataType)eType, ((IItemPropertyDescriptor.ValueHandlerProvider)itemPropertyDescriptor).getValueHandler(object)),
+                 false);
+          }
+          else
+          {
+            result =
+              new ExtendedComboBoxCellEditor
+                (composite, values, getEditLabelProvider(), itemPropertyDescriptor.isSortChoices(object), SWT.READ_ONLY, null, true);
+          }
         }
       }
       else if (eType instanceof EDataType)
       {
-        EDataType eDataType = (EDataType)eType;
+        final EDataType eDataType = (EDataType)eType;
         if (eDataType.isSerializable())
         {
           if (itemPropertyDescriptor.isMany(object))
           {
             final ILabelProvider editLabelProvider = getEditLabelProvider();
-            result = 
+            result =
               new ExtendedDialogCellEditor(composite, editLabelProvider)
               {
                 @Override
@@ -502,7 +1118,10 @@
                     null,
                     itemPropertyDescriptor.isMultiLine(object),
                     false,
-                    feature.isUnique());
+                    feature.isUnique(),
+                    itemPropertyDescriptor instanceof IItemPropertyDescriptor.ValueHandlerProvider ?
+                      ((IItemPropertyDescriptor.ValueHandlerProvider)itemPropertyDescriptor).getValueHandler(object) :
+                      null);
                   dialog.open();
                   return dialog.getResult();
                 }
@@ -510,19 +1129,15 @@
           }
           else if (eDataType.getInstanceClass() == Boolean.class) 
           {
-            result = new ExtendedComboBoxCellEditor(
-              composite,
-              Arrays.asList(new Object [] { null, Boolean.FALSE, Boolean.TRUE }),
-              getEditLabelProvider(),
-              itemPropertyDescriptor.isSortChoices(object));
+            return new CheckBoxCellEditor(composite, SWT.NONE, true);
           }
           else if (eDataType.getInstanceClass() == Boolean.TYPE)
           {
-            result = new ExtendedComboBoxCellEditor(
-              composite,
-              Arrays.asList(new Object [] { Boolean.FALSE, Boolean.TRUE }),
-              getEditLabelProvider(),
-              itemPropertyDescriptor.isSortChoices(object));
+            return new CheckBoxCellEditor(composite, SWT.NONE, false);
+          }
+          else if (itemPropertyDescriptor instanceof IItemPropertyDescriptor.ValueHandlerProvider)
+          {
+            result = createEDataTypeCellEditor(eDataType, ((IItemPropertyDescriptor.ValueHandlerProvider)itemPropertyDescriptor).getValueHandler(object), composite);
           }
           else
           {
diff --git a/plugins/org.eclipse.emf.edit.ui/src/org/eclipse/emf/edit/ui/provider/PropertySource.java b/plugins/org.eclipse.emf.edit.ui/src/org/eclipse/emf/edit/ui/provider/PropertySource.java
index 9fec260..ca7c56e 100644
--- a/plugins/org.eclipse.emf.edit.ui/src/org/eclipse/emf/edit/ui/provider/PropertySource.java
+++ b/plugins/org.eclipse.emf.edit.ui/src/org/eclipse/emf/edit/ui/provider/PropertySource.java
@@ -16,17 +16,16 @@
 import java.util.List;
 
 import org.eclipse.ui.views.properties.IPropertyDescriptor;
-import org.eclipse.ui.views.properties.IPropertySource;
-import org.eclipse.ui.views.properties.IPropertySource2;
 import org.eclipse.emf.edit.provider.IItemPropertyDescriptor;
 import org.eclipse.emf.edit.provider.IItemPropertySource;
+import org.eclipse.emf.edit.ui.view.ExtendedPropertySheetPage;
 
 
 /**
  * This is used to encapsulate an {@link IItemPropertySource} along with the object for which it is an item property source
  * and make it behave like an {@link org.eclipse.ui.views.properties.IPropertySource}.
  */
-public class PropertySource implements IPropertySource, IPropertySource2
+public class PropertySource implements ExtendedPropertySheetPage.IUnsettablePropertySource
 {
   /**
    * This is the object for which this class is a property source.
@@ -95,7 +94,7 @@
   }
 
   /**
-   * This returns <code>true</code> only when {@link IItemPropertyDescriptor#isPropertySet IItemPropertyDescriptor.isPropertySet} 
+   * This returns <code>true</code> only when {@link IItemPropertyDescriptor#isPropertySet IItemPropertyDescriptor.isPropertySet}
    * and {@link IItemPropertyDescriptor#canSetProperty IItemPropertyDescriptor.canSetProperty} are <code>true</code>.
    * @since 2.10
    */
@@ -120,4 +119,18 @@
   {
     itemPropertySource.getPropertyDescriptor(object, propertyId).setPropertyValue(object, value);
   }
+
+  /**
+   * This returns <code>true</code> only when {@link IItemPropertyDescriptor.ValueHandlerProvider#isPropertyUnsettable IItemPropertyDescriptor.ValueHandlerProvider.isPropertyUnsettable} 
+   * and {@link IItemPropertyDescriptor#canSetProperty IItemPropertyDescriptor.canSetProperty} are <code>true</code>.
+   * @since 2.14
+   */
+  public boolean isPropertyUnsettable(Object propertyId)
+  {
+    IItemPropertyDescriptor propertyDescriptor = itemPropertySource.getPropertyDescriptor(object, propertyId);
+    return 
+      propertyDescriptor.canSetProperty(object) && 
+        propertyDescriptor instanceof IItemPropertyDescriptor.ValueHandlerProvider &&
+        ((IItemPropertyDescriptor.ValueHandlerProvider)propertyDescriptor).isPropertyUnsettable(object);
+  }
 }
diff --git a/plugins/org.eclipse.emf.edit.ui/src/org/eclipse/emf/edit/ui/view/ExtendedPropertySheetPage.java b/plugins/org.eclipse.emf.edit.ui/src/org/eclipse/emf/edit/ui/view/ExtendedPropertySheetPage.java
index 3ea71ed..0891bc9 100644
--- a/plugins/org.eclipse.emf.edit.ui/src/org/eclipse/emf/edit/ui/view/ExtendedPropertySheetPage.java
+++ b/plugins/org.eclipse.emf.edit.ui/src/org/eclipse/emf/edit/ui/view/ExtendedPropertySheetPage.java
@@ -17,6 +17,8 @@
 import java.util.List;
 import java.util.Map;
 
+import org.eclipse.emf.common.ui.viewer.ColumnResizer;
+import org.eclipse.emf.common.ui.viewer.ColumnResizer.Handler;
 import org.eclipse.emf.common.util.Diagnostic;
 import org.eclipse.emf.ecore.EObject;
 import org.eclipse.emf.edit.domain.AdapterFactoryEditingDomain;
@@ -28,17 +30,30 @@
 import org.eclipse.emf.edit.ui.provider.PropertyDescriptor;
 import org.eclipse.jface.action.Action;
 import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.action.IContributionItem;
+import org.eclipse.jface.action.IContributionManagerOverrides;
 import org.eclipse.jface.action.IMenuManager;
 import org.eclipse.jface.action.IStatusLineManager;
 import org.eclipse.jface.action.IToolBarManager;
 import org.eclipse.jface.dialogs.IDialogSettings;
+import org.eclipse.jface.viewers.CellEditor;
 import org.eclipse.jface.viewers.ISelection;
 import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.StructuredSelection;
 import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
 import org.eclipse.swt.graphics.Image;
 import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Tree;
+import org.eclipse.swt.widgets.TreeItem;
 import org.eclipse.ui.IWorkbenchPart;
 import org.eclipse.ui.views.properties.IPropertyDescriptor;
+import org.eclipse.ui.views.properties.IPropertySource;
+import org.eclipse.ui.views.properties.IPropertySource2;
 import org.eclipse.ui.views.properties.IPropertySourceProvider;
 import org.eclipse.ui.views.properties.PropertySheetEntry;
 import org.eclipse.ui.views.properties.PropertySheetPage;
@@ -106,10 +121,63 @@
     }
   }
 
+  /**
+   * @since 2.14
+   */
+  protected static class SetValueAction extends Action
+  {
+    protected ExtendedPropertySheetEntry entry;
+
+    public SetValueAction()
+    {
+      setText(EMFEditUIPlugin.INSTANCE.getString("_UI_SetValue_action"));
+      setToolTipText(EMFEditUIPlugin.INSTANCE.getString("_UI_SetValue_action_tool_tip"));
+      setImageDescriptor(ExtendedImageRegistry.INSTANCE.getImageDescriptor(EMFEditUIPlugin.INSTANCE.getImage("full/elcl16/SetProperty.png")));
+      setDisabledImageDescriptor(ExtendedImageRegistry.INSTANCE.getImageDescriptor(EMFEditUIPlugin.INSTANCE.getImage("full/dlcl16/SetProperty.png")));
+    }
+
+    @Override
+    public void run()
+    {
+      entry.setPropertyValue();
+    }
+
+    public void setEntry(ExtendedPropertySheetEntry entry)
+    {
+      this.entry = entry;
+      setEnabled(entry != null && entry.isSetValueEnabled());
+    }
+  }
+
+  /**
+   * @since 2.14
+   */
+  protected SetValueAction setValueAction = new SetValueAction();
+
+  /**
+   * @since 2.14
+   */
+  protected  IAction restoreValueAction;
+
+  /**
+   * @since 2.14
+   */
+  protected int autoExpandLevel;
+
+  /**
+   * @since 2.14
+   */
+  protected boolean autoResizeColumns;
+
+  /**
+   * @since 2.14
+   */
+  protected Handler columnResizer;
+
+
   public ExtendedPropertySheetPage(AdapterFactoryEditingDomain editingDomain)
   {
-    super();
-    this.editingDomain = editingDomain;
+    this(editingDomain, Decoration.NONE, null, 0, false);
   }
 
   /**
@@ -117,7 +185,7 @@
    */
   public ExtendedPropertySheetPage(AdapterFactoryEditingDomain editingDomain, Decoration decoration)
   {
-    this(editingDomain, decoration, null);
+    this(editingDomain, decoration, null, 0, false);
   }
 
   /**
@@ -125,8 +193,19 @@
    */
   public ExtendedPropertySheetPage(AdapterFactoryEditingDomain editingDomain, Decoration decoration, IDialogSettings dialogSettings)
   {
-    this(editingDomain);
+    this(editingDomain, decoration, dialogSettings, 0, false);
+  }
+
+  /**
+   * @since 2.14
+   */
+  public ExtendedPropertySheetPage(AdapterFactoryEditingDomain editingDomain, Decoration decoration, IDialogSettings dialogSettings, int autoExpandLevel, boolean autoResizeColumns)
+  {
+    this.editingDomain = editingDomain;
     this.dialogSettings = dialogSettings;
+    this.autoExpandLevel = autoExpandLevel;
+    this.autoResizeColumns = autoResizeColumns;
+    this.autoResizeColumns = autoResizeColumns;
     diagnosticDecorator =  createDiagnosticDecorator(decoration);
   }
 
@@ -163,88 +242,33 @@
   public void createControl(Composite parent)
   {
     super.createControl(parent);
-    if (diagnosticDecorator != null)
-    {
-      class DecoratingPropertySheetEntry extends PropertySheetEntry
+
+    // Always create our extension of a property sheet entry.
+    //
+    ExtendedPropertySheetEntry decoratingPropertySheetEntry = new ExtendedPropertySheetEntry(diagnosticDecorator);
+    decoratingPropertySheetEntry.setPropertySourceProvider(propertySourceProvider);
+    setRootEntry(decoratingPropertySheetEntry);
+
+    // The property sheet page's viewer does not respond to widget selected events in a way that updates the current entry selection.
+    // This ensures that we can update the tool bar actions when the selection is changed via the keyboard.
+    //
+    final Tree tree = (Tree)getControl();
+    tree.addSelectionListener(new SelectionListener()
       {
-        @Override
-        protected PropertySheetEntry createChildEntry()
+        public void widgetSelected(SelectionEvent e)
         {
-          return new DecoratingPropertySheetEntry();
-        }
-    
-        @Override
-        public Image getImage()
-        {
-          Image image = super.getImage();
-          if (image == null)
-          {
-            image = ExtendedImageRegistry.INSTANCE.getImage(ItemPropertyDescriptor.GENERIC_VALUE_IMAGE);
-          }
-          Diagnostic featureDiagnostic = findDiagnostic();
-          return featureDiagnostic != null ? diagnosticDecorator.decorate(image, featureDiagnostic) : image;
-        }
-        
-        protected Diagnostic findDiagnostic()
-        {
-          IPropertyDescriptor descriptor = getDescriptor();
-          if (descriptor instanceof PropertyDescriptor)
-          {
-            Object feature = ((PropertyDescriptor)descriptor).getFeature();
-            Map<Object, ? extends Diagnostic> decorations = diagnosticDecorator.getDecorations();
-            if (!decorations.isEmpty() && feature != null)
-            {
-              for (Diagnostic diagnostic : decorations.values())
-              {
-                Diagnostic featureDiagnostic = find(diagnostic, feature);
-                if (featureDiagnostic != null)
-                {
-                  return featureDiagnostic;
-                }
-              }
-            }
-          }
-          return null;
+          Object data = e.item.getData();
+          handleEntrySelection(new StructuredSelection(data));
         }
 
-        protected Diagnostic find(Diagnostic diagnostic, Object feature)
+        public void widgetDefaultSelected(SelectionEvent e)
         {
-          // Gather them all...
-          //
-          if (diagnostic.getData().contains(feature))
-          {
-            return diagnostic;
-          }
-          for (Diagnostic child : diagnostic.getChildren())
-          {
-            Diagnostic result = find(child, feature);
-            if (result != null)
-            {
-              return result;
-            }
-          }
-          return null;
         }
+      });
 
-        @Override
-        public String getDescription()
-        {
-          String description = super.getDescription();
-          Diagnostic featureDiagnostic = findDiagnostic();
-          if (featureDiagnostic != null)
-          {
-            return description + " - " + DiagnosticDecorator.strip(featureDiagnostic.getMessage());
-          }
-          else
-          {
-            return description;
-          }
-        }
-      }
-
-      DecoratingPropertySheetEntry decoratingPropertySheetEntry = new DecoratingPropertySheetEntry();
-      decoratingPropertySheetEntry.setPropertySourceProvider(propertySourceProvider);
-      setRootEntry(decoratingPropertySheetEntry);
+    if (autoResizeColumns)
+    {
+      columnResizer = ColumnResizer.addColumnResizer(tree);
     }
   }
 
@@ -257,16 +281,127 @@
   }
 
   @Override
-  public void makeContributions(IMenuManager menuManager, IToolBarManager toolBarManager, IStatusLineManager statusLineManager)
+  public void makeContributions(IMenuManager menuManager, final IToolBarManager toolBarManager, IStatusLineManager statusLineManager)
   {
-    super.makeContributions(menuManager, toolBarManager, statusLineManager);
+    class DelegatingToolBarManager implements IToolBarManager
+    {
+      public void add(IAction action)
+      {
+        if ("defaults".equals(action.getId()))
+        {
+          restoreValueAction = action;
+          if (setValueAction != null)
+          {
+            toolBarManager.add(setValueAction);
+          }
+        }
+        toolBarManager.add(action);
+      }
+
+      public void add(IContributionItem item)
+      {
+        toolBarManager.add(item);
+      }
+
+      public void appendToGroup(String groupName, IAction action)
+      {
+        toolBarManager.appendToGroup(groupName, action);
+      }
+
+      public void appendToGroup(String groupName, IContributionItem item)
+      {
+        toolBarManager.appendToGroup(groupName, item);
+      }
+
+      public IContributionItem find(String id)
+      {
+        return toolBarManager.find(id);
+      }
+
+      public IContributionItem[] getItems()
+      {
+        return toolBarManager.getItems();
+      }
+
+      public IContributionManagerOverrides getOverrides()
+      {
+        return toolBarManager.getOverrides();
+      }
+
+      public void insertAfter(String id, IAction action)
+      {
+        toolBarManager.insertAfter(id, action);
+      }
+
+      public void insertAfter(String id, IContributionItem item)
+      {
+        toolBarManager.insertAfter(id, item);
+      }
+
+      public void insertBefore(String id, IAction action)
+      {
+        toolBarManager.insertBefore(id, action);
+      }
+
+      public void insertBefore(String id, IContributionItem item)
+      {
+        toolBarManager.insertBefore(id, item);
+      }
+
+      public boolean isDirty()
+      {
+        return toolBarManager.isDirty();
+      }
+
+      public boolean isEmpty()
+      {
+        return toolBarManager.isEmpty();
+      }
+
+      public void markDirty()
+      {
+        toolBarManager.markDirty();
+      }
+
+      public void prependToGroup(String groupName, IAction action)
+      {
+        toolBarManager.prependToGroup(groupName, action);
+      }
+
+      public void prependToGroup(String groupName, IContributionItem item)
+      {
+        toolBarManager.prependToGroup(groupName, item);
+      }
+
+      public IContributionItem remove(String id)
+      {
+        return toolBarManager.remove(id);
+      }
+
+      public IContributionItem remove(IContributionItem item)
+      {
+        return toolBarManager.remove(item);
+      }
+
+      public void removeAll()
+      {
+        toolBarManager.removeAll();
+      }
+
+      public void update(boolean force)
+      {
+        toolBarManager.update(force);
+      }
+    }
+
+    super.makeContributions(menuManager, new DelegatingToolBarManager(), statusLineManager);
     toolBarManager.add(locateValueAction);
   }
 
   @Override
   public void handleEntrySelection(ISelection selection)
   {
-    super.handleEntrySelection(selection);
+    ExtendedPropertySheetEntry entry = null;
     objectsToSelect.clear();
     if (!selection.isEmpty() && selection instanceof IStructuredSelection)
     {
@@ -274,9 +409,10 @@
       if (structuredSelection.size() == 1)
       {
         Object object = structuredSelection.getFirstElement();
-        if (object instanceof PropertySheetEntry)
+        if (object instanceof ExtendedPropertySheetEntry)
         {
-          PropertySheetEntry entry = (PropertySheetEntry)object;
+          entry = (ExtendedPropertySheetEntry)object;
+
           Object [] values = entry.getValues();
           if (values != null)
           {
@@ -303,7 +439,22 @@
         }
       }
     }
+
     locateValueAction.setEnabled(!objectsToSelect.isEmpty());
+
+    if (restoreValueAction == null || entry == null)
+    {
+      super.handleEntrySelection(selection);
+    }
+    else
+    {
+      restoreValueAction.setEnabled(entry.isRestoreValueEnabled());
+    }
+
+    if (setValueAction != null)
+    {
+      setValueAction.setEntry(entry);
+    }
   }
 
   protected void addObjectToSelect(Object object)
@@ -325,7 +476,40 @@
     {
       input = Collections.emptyList();
     }
+
     super.selectionChanged(part, selection);
+
+    if (autoExpandLevel != 0)
+    {
+      Tree tree = (Tree)getControl();
+      try
+      {
+        tree.setRedraw(false);
+        expand(tree, tree.getItems(), autoExpandLevel);
+      }
+      finally
+      {
+        tree.setRedraw(true);
+      }
+    }
+  }
+
+  private void expand(Tree tree, TreeItem[] items, int level)
+  {
+    if (level != 0)
+    {
+      for (TreeItem treeItem : items)
+      {
+        Event event = new Event();
+        event.item = treeItem;
+        if (!treeItem.getExpanded())
+        {
+          tree.notifyListeners(SWT.Expand, event);
+          treeItem.setExpanded(true);
+        }
+        expand(tree, treeItem.getItems(), level - 1);
+      }
+    }
   }
 
   /**
@@ -362,6 +546,10 @@
       viewerField.setAccessible(true);
       Viewer viewer = (Viewer)viewerField.get(this);
       viewer.refresh();
+      if (columnResizer != null)
+      {
+        columnResizer.resizeColumns();
+      }
       return;
     }
     catch (Throwable throwable)
@@ -371,4 +559,297 @@
 
     refresh();
   }
+
+  @Override
+  public void refresh()
+  {
+    Control control = getControl();
+    // Check that there isn't currently a cell editor active.
+    // If there is a focus control that isn't the control of the property sheet page...
+    Control focusControl = control.getDisplay().getFocusControl();
+    if (focusControl != null && focusControl != control)
+    {
+      // Check if that focus control is contained by the property sheet page's control.
+      for (Control parent = focusControl.getParent(); parent != null; parent = parent.getParent())
+      {
+        if (parent == control)
+        {
+          if (autoResizeColumns)
+          {
+            columnResizer.resizeColumns();
+          }
+
+          // If it is, then don't refresh the property sheet page
+          // because that will make the cell editor deactivate.
+          return;
+        }
+      }
+    }
+
+    // If it's a CCombo and the list (Shell) is active, the above logic won't find it.
+    if (setValueAction.entry != null && setValueAction.entry.editor != null && setValueAction.entry.editor.getControl() != null
+      && !setValueAction.entry.editor.getControl().isDisposed() && setValueAction.entry.editor.getControl().isFocusControl())
+    {
+      if (columnResizer != null)
+      {
+        columnResizer.resizeColumns();
+      }
+      return;
+    }
+
+    super.refresh();
+    if (columnResizer != null)
+    {
+      columnResizer.resizeColumns();
+    }
+  }
+
+  /**
+   * @since 2.14
+   */
+  public static class ExtendedPropertySheetEntry extends PropertySheetEntry
+  {
+    protected DiagnosticDecorator diagnosticDecorator;
+    
+    protected CellEditor editor;
+
+    public ExtendedPropertySheetEntry(DiagnosticDecorator diagnosticDecorator)
+    {
+      this.diagnosticDecorator = diagnosticDecorator;
+    }
+
+    @Override
+    protected PropertySheetEntry createChildEntry()
+    {
+      return new ExtendedPropertySheetEntry(diagnosticDecorator);
+    }
+
+    public boolean isRestoreValueEnabled()
+    {
+      PropertySheetEntry parent = getParent();
+      if (parent != null)
+      {
+        Object[] objects = parent.getValues();
+        IPropertyDescriptor descriptor = getDescriptor();
+        Object id = descriptor.getId();
+        for (Object object : objects)
+        {
+          IPropertySource source = getPropertySource(object);
+          for (IPropertyDescriptor propertyDescriptor : source.getPropertyDescriptors())
+          {
+            if (id.equals(propertyDescriptor.getId()))
+            {
+              if (source.isPropertySet(id) && (!(source instanceof IPropertySource2) || ((IPropertySource2)source).isPropertyResettable(id)))
+              {
+               return true;
+              }
+              else
+              {
+                break;
+              }
+            }
+          }
+        }
+      }
+      return false;
+    }
+
+    public boolean isSetValueEnabled()
+    {
+      PropertySheetEntry parent = getParent();
+      if (parent != null)
+      {
+        Object[] objects = parent.getValues();
+        IPropertyDescriptor descriptor = getDescriptor();
+        Object id = descriptor.getId();
+        for (Object object : objects)
+        {
+          IPropertySource source = getPropertySource(object);
+          for (IPropertyDescriptor propertyDescriptor : source.getPropertyDescriptors())
+          {
+            if (id.equals(propertyDescriptor.getId()))
+            {
+              if (!source.isPropertySet(id) && source instanceof IUnsettablePropertySource && ((IUnsettablePropertySource)source).isPropertyUnsettable(id))
+              {
+                return true;
+              }
+              else
+              {
+                break;
+              }
+            }
+          }
+        }
+      }
+      return false;
+    }
+
+    public void setPropertyValue()
+    {
+      PropertySheetEntry parent = getParent();
+      if (parent != null)
+      {
+        boolean change = false;
+        Object[] objects = parent.getValues();
+        IPropertyDescriptor descriptor = getDescriptor();
+        Object id = descriptor.getId();
+        for (int i = 0; i < objects.length; ++i)
+        {
+          Object object = objects[i];
+          IPropertySource source = getPropertySource(object);
+          Object value = getEditValue(i);
+          source.setPropertyValue(id, value);
+          change = true;
+        }
+        if (change)
+        {
+          refreshFromRoot();
+        }
+      }
+    }
+
+    @Override
+    public Image getImage()
+    {
+      Image image = super.getImage();
+      if (image == null)
+      {
+        image = ExtendedImageRegistry.INSTANCE.getImage(ItemPropertyDescriptor.GENERIC_VALUE_IMAGE);
+      }
+      Diagnostic featureDiagnostic = findDiagnostic();
+      return featureDiagnostic != null ? diagnosticDecorator.decorate(image, featureDiagnostic) : image;
+    }
+
+    protected Diagnostic findDiagnostic()
+    {
+      if (diagnosticDecorator != null)
+      {
+        IPropertyDescriptor descriptor = getDescriptor();
+        if (descriptor instanceof PropertyDescriptor)
+        {
+          Object feature = ((PropertyDescriptor)descriptor).getFeature();
+          Map<Object, ? extends Diagnostic> decorations = diagnosticDecorator.getDecorations();
+          if (!decorations.isEmpty() && feature != null)
+          {
+            for (Diagnostic diagnostic : decorations.values())
+            {
+              Diagnostic featureDiagnostic = find(diagnostic, feature);
+              if (featureDiagnostic != null)
+              {
+                return featureDiagnostic;
+              }
+            }
+          }
+        }
+      }
+      return null;
+    }
+
+    protected Diagnostic find(Diagnostic diagnostic, Object feature)
+    {
+      // Gather them all...
+      //
+      if (diagnostic.getData().contains(feature))
+      {
+        return diagnostic;
+      }
+      for (Diagnostic child : diagnostic.getChildren())
+      {
+        Diagnostic result = find(child, feature);
+        if (result != null)
+        {
+          return result;
+        }
+      }
+      return null;
+    }
+
+    @Override
+    public String getDescription()
+    {
+      String description = super.getDescription();
+      Diagnostic featureDiagnostic = findDiagnostic();
+      if (featureDiagnostic != null)
+      {
+        List<Diagnostic> children = featureDiagnostic.getChildren();
+        if (!children.isEmpty())
+        {
+          return description + " - " + DiagnosticDecorator.strip(children.get(0).getMessage());
+        }
+        else
+        {
+          return description + " - " + DiagnosticDecorator.strip(featureDiagnostic.getMessage());
+        }
+      }
+      else
+      {
+        return description;
+      }
+    }
+
+    /**
+     * This override guards the creation so it's only done if the current selection in the tree is the tree item for this property sheet entry.
+     * The framework listens for and handles the mouse down event using the point of that event to determine the tree item,
+     * but if the tree scrolls during an expansion, that point may not  be the tree item that was actually expanded but instead a tree item that's just been revealed.
+     * We really only want to create a cell editor for the actual selected tree item.
+     */
+    @Override
+    public CellEditor getEditor(Composite parent)
+    {
+      editor = null;
+      Tree tree = (Tree)parent;
+      TreeItem[] selection = tree.getSelection();
+      for (TreeItem treeItem : selection)
+      {
+        if (treeItem.getData() == this)
+        {
+          editor = super.getEditor(parent);
+          break;
+        }
+      }
+      return editor;
+    }
+
+    @Override
+    public void setValues(Object[] objects)
+    {
+      editor = null;
+      super.setValues(objects);
+    }
+
+    @Override
+    public void applyEditorValue()
+    {
+      if (editor != null && editor.isDirty())
+      {
+        super.applyEditorValue();
+      }
+    }
+  }
+
+  /**
+   *  An extension of the standard <code>{@link IPropertySource2}</code> interface.
+   * <p>
+   * This interface provides an extended API to allow a property to indicate whether or not it supports the concept of being in the <em>unset</em> state,
+   * i.e., to indicate that the value state of the property includes one additional state, the unset state, that is distinct from the set of values the property can have.
+   * For a property with {@link IPropertyDescriptor#getId() ID} <code>x</code> that returns <code>true</code> for <code>{@link #isPropertyUnsettable(Object) isPropertyUnsettable}(x)</code>
+   * and that returns <code>false</code> for <code>{@link #isPropertySet(Object) isPropertySet}(x)</code>,
+   * calling <code>{@link #setPropertyValue(Object, Object) setPropertyValue}(x, {@link #getEditableValue getEditableValue}(x)</code>
+   * will result in <code>isPropertySet(true)</code> becoming <code>true</code>, even though in both states the property has the same value.
+   * Such a property <code>x</code> will always return <code>false</code> for <code>isPropertySet(x)</code> after a call to  <code>{@link #resetPropertyValue(Object) resetPropertyValue}(x)</code>.
+   * A property <code>x</code> that is read-only will always return <code>false</code> for <code>isPropertyUnsettable(x)</code>.
+   * </p>
+   *
+   * @since 2.14
+   */
+  public interface IUnsettablePropertySource extends IPropertySource2
+  {
+    /**
+     * Returns whether the property supports the concept of being in the <em>{@link IUnsettablePropertySource unset}</em> state.
+     * @param id the ID of the property.
+     * @return whether the property supports the concept of being in the unset.
+     * @see IUnsettablePropertySource
+     */
+    boolean isPropertyUnsettable(Object id);
+  }
 }
diff --git a/plugins/org.eclipse.emf.edit/icons/full/obj16/NoValue.gif b/plugins/org.eclipse.emf.edit/icons/full/obj16/NoValue.gif
new file mode 100644
index 0000000..69ad632
--- /dev/null
+++ b/plugins/org.eclipse.emf.edit/icons/full/obj16/NoValue.gif
Binary files differ
diff --git a/plugins/org.eclipse.emf.edit/src/org/eclipse/emf/edit/provider/IItemPropertyDescriptor.java b/plugins/org.eclipse.emf.edit/src/org/eclipse/emf/edit/provider/IItemPropertyDescriptor.java
index afd368c..3f93c16 100644
--- a/plugins/org.eclipse.emf.edit/src/org/eclipse/emf/edit/provider/IItemPropertyDescriptor.java
+++ b/plugins/org.eclipse.emf.edit/src/org/eclipse/emf/edit/provider/IItemPropertyDescriptor.java
@@ -18,18 +18,72 @@
  * This interface extends IPropertyDescriptor so that the methods of {@link IItemPropertySource} can be delegated to the descriptor.
  * This allows the implementing class to completely encapsulate the work associated with supporting a particular property sheet property.
  */
-public interface IItemPropertyDescriptor 
+public interface IItemPropertyDescriptor
 {
   /**
+   * An interface that may be implemented by property descriptor to specialize the handling of entered literals and values.
+   * 
+   * @since 2.14
+   */
+  public interface ValueHandlerProvider
+  {
+    /**
+     * Returns the value handler.
+     * This must not be <code>null</code> if {@link #isChoiceArbitrary(Object)} return <code>true</code>.
+     */
+    public ValueHandler getValueHandler(Object object);
+
+    /**
+     * Returns whether this property descriptor allows arbitrary values
+     * in addition to the explicit {@link IItemPropertyDescriptor#getChoiceOfValues(Object) choices} provided.
+     */
+    public boolean isChoiceArbitrary(Object object);
+
+    /**
+     * Returns whether this property descriptor supports the concept of an <em>unset</em> state,
+     * i.e., whether the value state of the property includes one additional state, the unset state, that is distinct from the set of values the property can have.
+     */
+    public boolean isPropertyUnsettable(Object object);
+  }
+
+  /**
+   * An interface used by by property descriptors to specialize the validation and handling of entered literals and values.
+   * 
+   * @since 2.14
+   */
+  public interface ValueHandler
+  {
+    /**
+     * Converts a literal value to an instance value.
+     * @param literal the literal textual value.
+     * @return the instance value.
+     * @see #toString(Object)
+     */
+    public Object toValue(String literal);
+
+    /**
+     * Converts an instance value to literal value.
+     * @param instance the instance value.
+     * @return the literal value.
+     * @see #toString(Object)
+     */
+    public String toString(Object instance);
+
+    /**
+     * Validates the literal value, returning <code>null</code> if the literal is valid and a description of why it's invalid otherwise.
+     * @param literal the literal value.
+     * @return returns <code>null</code> if the literal is valid and a description of why it's invalid otherwise.
+     */
+    public String isValid(String literal);
+  }
+
+  /**
    * This fetches this descriptor's property from the object.
-   * Sometimes it's necessary to update the contents of the cell editor during this call,
-   * i.e., the call is used as a notification that this descriptor is being used to edit another object.
    */
   public Object getPropertyValue(Object object);
 
   /**
    * This determines whether this descriptor's property for the object is set.
-   * I'm not sure right now what this is used for?  I should find out.
    */
   public boolean isPropertySet(Object object);
 
@@ -50,7 +104,7 @@
 
   /**
    * Returns the name of the category to which this property belongs.
-   */ 
+   */
   String getCategory(Object object);
 
   /**
@@ -86,7 +140,7 @@
   /**
    * Returns whether this property descriptor and the given one are compatible.
    */
-  boolean isCompatibleWith(Object object, Object anotherObject,  IItemPropertyDescriptor anotherPropertyDescriptor);
+  boolean isCompatibleWith(Object object, Object anotherObject, IItemPropertyDescriptor anotherPropertyDescriptor);
 
   /**
    * Returns the feature.
@@ -103,7 +157,7 @@
    * Returns the choices of all the values that this property may take one.
    */
   public Collection<?> getChoiceOfValues(Object object);
-  
+
   /**
    * Returns whether this property's value will consist of multi-line text.
    * @since 2.2.0
diff --git a/plugins/org.eclipse.emf.edit/src/org/eclipse/emf/edit/provider/ItemPropertyDescriptor.java b/plugins/org.eclipse.emf.edit/src/org/eclipse/emf/edit/provider/ItemPropertyDescriptor.java
index 3d085db..3bb4c0a 100644
--- a/plugins/org.eclipse.emf.edit/src/org/eclipse/emf/edit/provider/ItemPropertyDescriptor.java
+++ b/plugins/org.eclipse.emf.edit/src/org/eclipse/emf/edit/provider/ItemPropertyDescriptor.java
@@ -25,6 +25,7 @@
 import org.eclipse.emf.common.command.Command;
 import org.eclipse.emf.common.command.CompoundCommand;
 import org.eclipse.emf.common.notify.AdapterFactory;
+import org.eclipse.emf.common.util.Diagnostic;
 import org.eclipse.emf.common.util.Enumerator;
 import org.eclipse.emf.common.util.ResourceLocator;
 import org.eclipse.emf.common.util.TreeIterator;
@@ -42,6 +43,7 @@
 import org.eclipse.emf.ecore.EcorePackage;
 import org.eclipse.emf.ecore.resource.Resource;
 import org.eclipse.emf.ecore.resource.ResourceSet;
+import org.eclipse.emf.ecore.util.Diagnostician;
 import org.eclipse.emf.ecore.util.EcoreUtil;
 import org.eclipse.emf.ecore.util.ExtendedMetaData;
 import org.eclipse.emf.ecore.util.FeatureMap;
@@ -58,7 +60,7 @@
  * This implementation of an item property descriptor supports delegating of the {@link IItemPropertySource} interface
  * to the {@link IItemPropertyDescriptor} interface.
  */
-public class ItemPropertyDescriptor implements IItemPropertyDescriptor, OverrideableCommandOwner
+public class ItemPropertyDescriptor implements IItemPropertyDescriptor, OverrideableCommandOwner, IItemPropertyDescriptor.ValueHandlerProvider
 {
   /**
    * Returns the feature's default {@link #getId(Object) identifier}.
@@ -77,6 +79,11 @@
   public static final Object TEXT_VALUE_IMAGE = EMFEditPlugin.INSTANCE.getImage("full/obj16/TextValue");
 
   /**
+   * @since 2.14
+   */
+  public static final Object NO_VALUE_IMAGE = EMFEditPlugin.INSTANCE.getImage("full/obj16/NoValue");
+
+  /**
    * For now we need to keep track of the adapter factory, because we need it to provide a correct label provider.
    */
   protected AdapterFactory adapterFactory;
@@ -1362,12 +1369,11 @@
   }
 
   /**
-   * This does the delegated job of determine whether the property value from the given object is set.
+   * This does the delegated job of determining whether the property value from the given object is set.
    * It is implemented in a generic way using the structural feature.
    */
   public boolean isPropertySet(Object object)
   {
-    // System.out.println("isPropertySet " + object);
     EObject eObject = (EObject)object;
 
     if (parentReferences != null)
@@ -1385,12 +1391,7 @@
     {
       try
       {
-        return 
-          feature instanceof EAttribute ? 
-            feature.isMany() ?
-              !((List<?>)eObject.eGet(feature)).isEmpty() : 
-              eObject.eIsSet(feature) : 
-            eObject.eGet(feature) != null;
+        return eObject.eIsSet(feature);
       }
       catch (Throwable exception)
       {
@@ -1400,6 +1401,26 @@
   }
 
   /**
+   * This does the delegated job of determining whether the property supports the concept of an unset state.
+   * It is implemented in a generic way using the structural feature.
+   *
+   * @see EStructuralFeature#isUnsettable()
+   *
+   * @since 2.14
+   */
+  public boolean isPropertyUnsettable(Object object)
+  {
+    if (parentReferences != null)
+    {
+      return false;
+    }
+    else
+    {
+      return feature.isUnsettable();
+    }
+  }
+
+  /**
    * This determines whether this descriptor's property for the object supports set (and reset).
    */
   public boolean canSetProperty(Object object)
@@ -1646,4 +1667,82 @@
   {
     return sortChoices;
   }
+
+  /**
+   * @since 2.14
+   */
+  public boolean isChoiceArbitrary(Object object)
+  {
+    return false;
+  }
+
+  /**
+   * @since 2.14
+   */
+  public ValueHandler getValueHandler(Object object)
+  {
+    return feature instanceof EAttribute ? new DataTypeValueHandler((EDataType)feature.getEType()) : null;
+  }
+
+  /**
+   * @since 2.14
+   */
+  public static class DataTypeValueHandler implements ValueHandler
+  {
+    protected final EDataType eDataType;
+
+    public DataTypeValueHandler(EDataType eDataType)
+    {
+      this.eDataType = eDataType;
+    }
+
+    protected Diagnostic validate(EDataType eDataType, Object instance)
+    {
+      Diagnostic diagnostic = Diagnostician.INSTANCE.validate(eDataType, instance);
+      return diagnostic;
+    }
+
+    public String isValid(String literal)
+    {
+      Object value;
+      try
+      {
+        value = eDataType.getEPackage().getEFactoryInstance().createFromString(eDataType, literal);
+      }
+      catch (Exception exception)
+      {
+        String message = exception.getClass().getName();
+        int index = message.lastIndexOf('.');
+        if (index >= 0)
+        {
+          message = message.substring(index + 1);
+        }
+        if (exception.getLocalizedMessage() != null)
+        {
+          message = message + ": " + exception.getLocalizedMessage();
+        }
+        return message;
+      }
+      Diagnostic diagnostic = validate(eDataType, value);
+      if (diagnostic.getSeverity() == Diagnostic.OK)
+      {
+        return null;
+      }
+      else
+      {
+        return (diagnostic.getChildren().get(0)).getMessage();
+      }
+    }
+
+    public Object toValue(String string)
+    {
+        return EcoreUtil.createFromString(eDataType, string);
+    }
+
+    public String toString(Object value)
+    {
+      String result = EcoreUtil.convertToString(eDataType, value);
+      return result == null ? "" : result;
+    }
+  }
 }
diff --git a/plugins/org.eclipse.emf.edit/src/org/eclipse/emf/edit/provider/ItemPropertyDescriptorDecorator.java b/plugins/org.eclipse.emf.edit/src/org/eclipse/emf/edit/provider/ItemPropertyDescriptorDecorator.java
index db1d74a..703f79e 100644
--- a/plugins/org.eclipse.emf.edit/src/org/eclipse/emf/edit/provider/ItemPropertyDescriptorDecorator.java
+++ b/plugins/org.eclipse.emf.edit/src/org/eclipse/emf/edit/provider/ItemPropertyDescriptorDecorator.java
@@ -16,7 +16,7 @@
 
 /**
  */
-public class ItemPropertyDescriptorDecorator implements IItemPropertyDescriptor
+public class ItemPropertyDescriptorDecorator implements IItemPropertyDescriptor, IItemPropertyDescriptor.ValueHandlerProvider
 {
   protected Object object;
   protected IItemPropertyDescriptor itemPropertyDescriptor;
@@ -110,6 +110,16 @@
   }
 
   /**
+   * This does the delegated job of determining whether the property supports the concept of an unset state.
+   *
+   * @since 2.14
+   */
+  public boolean isPropertyUnsettable(Object object)
+  {
+    return itemPropertyDescriptor instanceof IItemPropertyDescriptor.ValueHandlerProvider && ((IItemPropertyDescriptor.ValueHandlerProvider)itemPropertyDescriptor).isPropertyUnsettable(object);
+  }
+
+  /**
    * This does the delegated job of determining whether the property value from the given object supports set (and reset).
    */
   public boolean canSetProperty(Object thisObject)
@@ -151,7 +161,7 @@
   {
     return itemPropertyDescriptor.isMany(thisObject);
   }
-  
+
   /**
    * This does the delegated job of determining whether the property's value consists of multi-line text.
    * @since 2.2.0
@@ -169,4 +179,20 @@
   {
     return itemPropertyDescriptor.isSortChoices(object);
   }
+
+  /**
+   * @since 2.14
+   */
+  public boolean isChoiceArbitrary(Object object)
+  {
+    return itemPropertyDescriptor instanceof ValueHandlerProvider && ((ValueHandlerProvider)itemPropertyDescriptor).isChoiceArbitrary(object);
+  }
+
+  /**
+   * @since 2.14
+   */
+  public ValueHandler getValueHandler(Object object)
+  {
+    return itemPropertyDescriptor instanceof ValueHandlerProvider ? ((ValueHandlerProvider)itemPropertyDescriptor).getValueHandler(object) : null;
+  }
 }
diff --git a/tests/org.eclipse.emf.test.ecore.xcore/src/org/eclipse/emf/test/ecore/xcore/genmodel/XcoreGenModelTest.java b/tests/org.eclipse.emf.test.ecore.xcore/src/org/eclipse/emf/test/ecore/xcore/genmodel/XcoreGenModelTest.java
index 86b8152..1cb3a81 100644
--- a/tests/org.eclipse.emf.test.ecore.xcore/src/org/eclipse/emf/test/ecore/xcore/genmodel/XcoreGenModelTest.java
+++ b/tests/org.eclipse.emf.test.ecore.xcore/src/org/eclipse/emf/test/ecore/xcore/genmodel/XcoreGenModelTest.java
@@ -9,6 +9,7 @@
 
 
 import org.eclipse.emf.codegen.ecore.genmodel.GenBase;
+import org.eclipse.emf.ecore.EStructuralFeature;
 import org.eclipse.emf.ecore.util.EcoreUtil;
 import org.eclipse.emf.ecore.xcore.XNamedElement;
 import org.eclipse.emf.ecore.xcore.mappings.XcoreMapper;
@@ -59,6 +60,13 @@
   {
     EcoreUtil.resolveAll(resource);
     GenBase gen = mapper.getGen((XNamedElement)offset.getEObject());
+    EStructuralFeature eStructuralFeature = gen.eClass().getEStructuralFeature("documentation");
+    if (eStructuralFeature != null)
+    {
+      // Clear the documentation feature because this will have the Xpect documentation tag which we don't want to format.
+      //
+      gen.eSet(eStructuralFeature, null);
+    }
     return new GenModelFormatter().resolveCrossReferences().format(gen);
   }
 
diff --git a/tests/org.eclipse.emf.test.ecore.xcore/src/org/eclipse/emf/test/ecore/xcore/scoping/LazyGenModelInferenceTest.java b/tests/org.eclipse.emf.test.ecore.xcore/src/org/eclipse/emf/test/ecore/xcore/scoping/LazyGenModelInferenceTest.java
index ec3a683..3511d6d 100644
--- a/tests/org.eclipse.emf.test.ecore.xcore/src/org/eclipse/emf/test/ecore/xcore/scoping/LazyGenModelInferenceTest.java
+++ b/tests/org.eclipse.emf.test.ecore.xcore/src/org/eclipse/emf/test/ecore/xcore/scoping/LazyGenModelInferenceTest.java
@@ -103,6 +103,7 @@
       return contents;
     }
 
+    @Override
     public boolean isFullyInitialized()
     {
       return fullyInitialized;
diff --git a/tests/org.eclipse.emf.test.ecore.xcore/test-models/org/eclipse/emf/test/ecore/xcore/genmodel/GenFeatures1.xcore b/tests/org.eclipse.emf.test.ecore.xcore/test-models/org/eclipse/emf/test/ecore/xcore/genmodel/GenFeatures1.xcore
index b115d8b..c5b8feb 100644
--- a/tests/org.eclipse.emf.test.ecore.xcore/test-models/org/eclipse/emf/test/ecore/xcore/genmodel/GenFeatures1.xcore
+++ b/tests/org.eclipse.emf.test.ecore.xcore/test-models/org/eclipse/emf/test/ecore/xcore/genmodel/GenFeatures1.xcore
@@ -4,6 +4,7 @@
 {
 	/* XPECT genBase at x ---
 		GenFeature {
+			documentation = null
 			notify = 'false'
 			createChild = 'false'
 			propertySortChoices = 'true'
@@ -14,6 +15,7 @@
 	   
 	/* XPECT genBase at y ---
 		GenFeature {
+			documentation = null
 			notify = 'false'
 			createChild = 'false'
 			propertySortChoices = 'true'
diff --git a/tests/org.eclipse.emf.test.ecore.xcore/test-models/org/eclipse/emf/test/ecore/xcore/genmodel/GenPackage1.xcore b/tests/org.eclipse.emf.test.ecore.xcore/test-models/org/eclipse/emf/test/ecore/xcore/genmodel/GenPackage1.xcore
index 904a6e5..b68f5aa 100644
--- a/tests/org.eclipse.emf.test.ecore.xcore/test-models/org/eclipse/emf/test/ecore/xcore/genmodel/GenPackage1.xcore
+++ b/tests/org.eclipse.emf.test.ecore.xcore/test-models/org/eclipse/emf/test/ecore/xcore/genmodel/GenPackage1.xcore
@@ -12,6 +12,7 @@
 		genClassifiers -> [
 			GenClass genPackage1.Bar
 		]
+		documentation = null
 	}
 ---
 */
diff --git a/tests/org.eclipse.emf.test.examples/data/htmlExporter/multipackage_library.ecore b/tests/org.eclipse.emf.test.examples/data/htmlExporter/multipackage_library.ecore
index 317c43d..ab69f85 100644
--- a/tests/org.eclipse.emf.test.examples/data/htmlExporter/multipackage_library.ecore
+++ b/tests/org.eclipse.emf.test.examples/data/htmlExporter/multipackage_library.ecore
@@ -1,8 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<ecore:EPackage xmi:version="2.0"
-    xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-    xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" name="library"
-    nsURI="http:///org/eclipse/example/multipackage_library.ecore" nsPrefix="org.eclipse.example.library">
+<ecore:EPackage xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" name="library" nsURI="http:///org/eclipse/example/multipackage_library.ecore"
+    nsPrefix="org.eclipse.example.library">
   <eAnnotations source="http://www.eclipse.org/emf/2002/GenModel">
     <details key="documentation" value="This is a single line, non-formatted comment for the library package"/>
   </eAnnotations>
@@ -13,11 +12,7 @@
     <eAnnotations source="http://www.eclipse.org/emf/2002/Ecore">
       <details key="constraints" value="BookConstraint1 BookConstraint2"/>
     </eAnnotations>
-    <eStructuralFeatures xsi:type="ecore:EAttribute" name="title" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString">
-      <eAnnotations source="http://www.eclipse.org/emf/2002/Ecore">
-        <details key="constraints" value="Book_TitleConstraint1"/>
-      </eAnnotations>
-    </eStructuralFeatures>
+    <eStructuralFeatures xsi:type="ecore:EAttribute" name="title" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
     <eStructuralFeatures xsi:type="ecore:EAttribute" name="pages" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EInt"
         defaultValueLiteral="100">
       <eAnnotations source="http://www.eclipse.org/emf/2002/GenModel">
@@ -30,9 +25,6 @@
       <eAnnotations source="http://www.eclipse.org/emf/2002/GenModel">
         <details key="documentation" value="A really, really long documentation for book.author. This text is not formatted. And it is written in a single line. We are using it to check if it is properly displayed. It certainly can get ugly but we will try to make it as pretty as possible. Oh my, more than 300 columns of pure mumbling... This should be a new record..."/>
       </eAnnotations>
-      <eAnnotations source="http://www.eclipse.org/emf/2002/Ecore">
-        <details key="constraints" value="Book_AuthorConstraint1"/>
-      </eAnnotations>
     </eStructuralFeatures>
   </eClassifiers>
   <eClassifiers xsi:type="ecore:EEnum" name="BookCategory">
@@ -55,9 +47,6 @@
       <eAnnotations source="http://www.eclipse.org/emf/2002/GenModel">
         <details key="documentation" value="&lt;p>A &lt;b>formatted&lt;/b> comment that includes &lt;br />&#xD;&#xA;some line&lt;br />&#xD;&#xA;breaks.&lt;/p>&#xD;&#xA;&lt;p>And a paragraph too!&lt;/p>"/>
       </eAnnotations>
-      <eAnnotations source="http://www.eclipse.org/emf/2002/Ecore">
-        <details key="constraints" value="Library_ReserveConstraint1 Library_ReserveConstraint2 Library_ReserveConstraint3 Library_ReserveConstraint4"/>
-      </eAnnotations>
       <eParameters name="books" upperBound="-1" eType="#//Book"/>
     </eOperations>
     <eStructuralFeatures xsi:type="ecore:EAttribute" name="name" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
diff --git a/tests/org.eclipse.emf.test.examples/data/htmlExporter/multipackage_library.html b/tests/org.eclipse.emf.test.examples/data/htmlExporter/multipackage_library.html
index bda27ac..f1b5d0c 100644
--- a/tests/org.eclipse.emf.test.examples/data/htmlExporter/multipackage_library.html
+++ b/tests/org.eclipse.emf.test.examples/data/htmlExporter/multipackage_library.html
@@ -98,16 +98,15 @@
 							<input type="checkbox" name="detailCheckbox" value="detail1" onclick="javascript:openSection(this.value, this.checked)"/> <i><b>EString</b></i> <a name="Book@title">title</a>
 							<div id="detail1" name="detail1" style="overflow:hidden;display:none">
 								<table class="details">
-									<tr class="odd"><td class="left">constraints</td><td class="right"><tt>Book_TitleConstraint1</tt></td></tr>
-									<tr class="even"><td class="left">lowerBound</td><td class="right"><tt>0</tt></td></tr>
-									<tr class="odd"><td class="left">upperBound</td><td class="right"><tt>1</tt></td></tr>
-									<tr class="even"><td class="left">changeable</td><td class="right"><tt>true</tt></td></tr>
-									<tr class="odd"><td class="left">defaultValue</td><td class="right"><tt>null</tt></td></tr>
-									<tr class="even"><td class="left">derived</td><td class="right"><tt>false</tt></td></tr>
-									<tr class="odd"><td class="left">transient</td><td class="right"><tt>false</tt></td></tr>
-									<tr class="even"><td class="left">unsettable</td><td class="right"><tt>false</tt></td></tr>
-									<tr class="odd"><td class="left">volatile</td><td class="right"><tt>false</tt></td></tr>
-									<tr class="even"><td class="left">iD</td><td class="right"><tt>false</tt></td></tr>
+									<tr class="odd"><td class="left">lowerBound</td><td class="right"><tt>0</tt></td></tr>
+									<tr class="even"><td class="left">upperBound</td><td class="right"><tt>1</tt></td></tr>
+									<tr class="odd"><td class="left">changeable</td><td class="right"><tt>true</tt></td></tr>
+									<tr class="even"><td class="left">defaultValue</td><td class="right"><tt>null</tt></td></tr>
+									<tr class="odd"><td class="left">derived</td><td class="right"><tt>false</tt></td></tr>
+									<tr class="even"><td class="left">transient</td><td class="right"><tt>false</tt></td></tr>
+									<tr class="odd"><td class="left">unsettable</td><td class="right"><tt>false</tt></td></tr>
+									<tr class="even"><td class="left">volatile</td><td class="right"><tt>false</tt></td></tr>
+									<tr class="odd"><td class="left">iD</td><td class="right"><tt>false</tt></td></tr>
 								</table><br />
 							</div>
 						</li>
@@ -154,19 +153,18 @@
 							<div id="detail4" name="detail4" style="overflow:hidden;display:none">
 								<table class="details">
 									<tr class="documentation"><td class="left" colspan="2">A really, really long documentation for book.author. This text is not formatted. And it is written in a single line. We are using it to check if it is properly displayed. It certainly can get ugly but we will try to make it as pretty as possible. Oh my, more than 300 columns of pure mumbling... This should be a new record...</td></tr>
-									<tr class="odd"><td class="left">constraints</td><td class="right"><tt>Book_AuthorConstraint1</tt></td></tr>
-									<tr class="even"><td class="left">opposite</td><td class="right"><a href="library.people.html#Writer@books" title="Reference:Writer.books">books</a></td></tr> 
-									<tr class="odd"><td class="left">containment</td><td class="right"><tt>false</tt></td></tr>
-									<tr class="even"><td class="left">container</td><td class="right"><tt>false</tt></td></tr>
-									<tr class="odd"><td class="left">resolveProxies</td><td class="right"><tt>true</tt></td></tr>
-									<tr class="even"><td class="left">lowerBound</td><td class="right"><tt>0</tt></td></tr>
-									<tr class="odd"><td class="left">upperBound</td><td class="right"><tt>1</tt></td></tr>
-									<tr class="even"><td class="left">changeable</td><td class="right"><tt>true</tt></td></tr>
-									<tr class="odd"><td class="left">defaultValue</td><td class="right"><tt>null</tt></td></tr>
-									<tr class="even"><td class="left">derived</td><td class="right"><tt>false</tt></td></tr>
-									<tr class="odd"><td class="left">transient</td><td class="right"><tt>false</tt></td></tr>
-									<tr class="even"><td class="left">unsettable</td><td class="right"><tt>false</tt></td></tr>
-									<tr class="odd"><td class="left">volatile</td><td class="right"><tt>false</tt></td></tr>
+									<tr class="odd"><td class="left">opposite</td><td class="right"><a href="library.people.html#Writer@books" title="Reference:Writer.books">books</a></td></tr> 
+									<tr class="even"><td class="left">containment</td><td class="right"><tt>false</tt></td></tr>
+									<tr class="odd"><td class="left">container</td><td class="right"><tt>false</tt></td></tr>
+									<tr class="even"><td class="left">resolveProxies</td><td class="right"><tt>true</tt></td></tr>
+									<tr class="odd"><td class="left">lowerBound</td><td class="right"><tt>0</tt></td></tr>
+									<tr class="even"><td class="left">upperBound</td><td class="right"><tt>1</tt></td></tr>
+									<tr class="odd"><td class="left">changeable</td><td class="right"><tt>true</tt></td></tr>
+									<tr class="even"><td class="left">defaultValue</td><td class="right"><tt>null</tt></td></tr>
+									<tr class="odd"><td class="left">derived</td><td class="right"><tt>false</tt></td></tr>
+									<tr class="even"><td class="left">transient</td><td class="right"><tt>false</tt></td></tr>
+									<tr class="odd"><td class="left">unsettable</td><td class="right"><tt>false</tt></td></tr>
+									<tr class="even"><td class="left">volatile</td><td class="right"><tt>false</tt></td></tr>
 								</table><br />
 							</div>
 						</li>
@@ -280,9 +278,8 @@
 some line<br />
 breaks.</p>
 <p>And a paragraph too!</p></td></tr>
-									<tr class="odd"><td class="left">constraints</td><td class="right"><tt>Library_ReserveConstraint1</tt>, <tt>Library_ReserveConstraint2</tt>, <tt>Library_ReserveConstraint3</tt>, <tt>Library_ReserveConstraint4</tt></td></tr>
-									<tr class="even"><td class="left">lowerBound</td><td class="right"><tt>0</tt></td></tr>
-									<tr class="odd"><td class="left">upperBound</td><td class="right"><tt>1</tt></td></tr>
+									<tr class="odd"><td class="left">lowerBound</td><td class="right"><tt>0</tt></td></tr>
+									<tr class="even"><td class="left">upperBound</td><td class="right"><tt>1</tt></td></tr>
 								</table><br />
 							</div>
 						</li>