diff --git a/core/lib/Drupal/Core/Config/Schema/ArrayElement.php b/core/lib/Drupal/Core/Config/Schema/ArrayElement.php
index f801c28..4d9711e 100644
--- a/core/lib/Drupal/Core/Config/Schema/ArrayElement.php
+++ b/core/lib/Drupal/Core/Config/Schema/ArrayElement.php
@@ -12,6 +12,7 @@
 use \Countable;
 use \IteratorAggregate;
 use \Traversable;
+use Drupal\Core\TypedData\PrimitiveInterface;
 
 /**
  * Defines a generic configuration element that contains multiple properties.
@@ -55,7 +56,7 @@ protected function getAllKeys() {
   protected abstract function parse();
 
   /**
-   * Implements TypedDataInterface::validate().
+   * {@inheritdoc}
    */
   public function validate() {
     foreach ($this->getElements() as $element) {
@@ -85,7 +86,7 @@ public function offsetGet($offset) {
    * Implements ArrayAccess::offsetSet().
    */
   public function offsetSet($offset, $value) {
-    if ($value instanceof TypedDataInterface) {
+    if ($value instanceof PrimitiveInterface) {
       $value = $value->getValue();
     }
     $this->value[$offset] = $value;
diff --git a/core/lib/Drupal/Core/Config/Schema/Element.php b/core/lib/Drupal/Core/Config/Schema/Element.php
index d4e29db..bb748cf 100644
--- a/core/lib/Drupal/Core/Config/Schema/Element.php
+++ b/core/lib/Drupal/Core/Config/Schema/Element.php
@@ -28,4 +28,27 @@ protected function parseElement($key, $data, $definition) {
     return config_typed()->create($definition, $data, $key, $this);
   }
 
+  /**
+   * @todo
+   *   Temporarily copied this method from TypedData where it's been removed
+   *   because TypedDataInterface is removed. This will be fixed with
+   *   https://drupal.org/node/1928868
+   */
+  public function getValue() {
+    return $this->value;
+  }
+
+  /**
+   * @todo
+   *   Temporarily copied this method from TypedData where it's been removed
+   *   because TypedDataInterface is removed. This will be fixed with
+   *   https://drupal.org/node/1928868
+   */
+  public function setValue($value, $notify = TRUE) {
+    $this->value = $value;
+    // Notify the parent of any changes.
+    if ($notify && isset($this->parent)) {
+      $this->parent->onChange($this->name);
+    }
+  }
 }
diff --git a/core/lib/Drupal/Core/Config/Schema/Mapping.php b/core/lib/Drupal/Core/Config/Schema/Mapping.php
index b7bddb3..1509421 100644
--- a/core/lib/Drupal/Core/Config/Schema/Mapping.php
+++ b/core/lib/Drupal/Core/Config/Schema/Mapping.php
@@ -9,7 +9,6 @@
 
 use Drupal\Component\Utility\NestedArray;
 use Drupal\Core\TypedData\ComplexDataInterface;
-use Drupal\Core\TypedData\TypedDataInterface;
 use \InvalidArgumentException;
 
 /**
@@ -53,15 +52,11 @@ public function get($property_name) {
    * Implements Drupal\Core\TypedData\ComplexDataInterface::set().
    */
   public function set($property_name, $value, $notify = TRUE) {
-    // Notify the parent of any changes to be made.
-    if ($notify && isset($this->parent)) {
-      $this->parent->onChange($this->name);
-    }
     // Set the data into the configuration array but behave according to the
     // interface specification when we've got a null value.
     if (isset($value)) {
       $this->value[$property_name] = $value;
-      return $this->get($property_name);
+      $property = $this->get($property_name);
     }
     else {
       // In these objects, when clearing the value, the property is gone.
@@ -69,8 +64,12 @@ public function set($property_name, $value, $notify = TRUE) {
       $property = $this->get($property_name);
       unset($this->value[$property_name]);
       $property->setValue($value);
-      return $property;
     }
+    // Notify the parent of any changes.
+    if ($notify && isset($this->parent)) {
+      $this->parent->onChange($this->name);
+    }
+    return $property;
   }
 
   /**
diff --git a/core/lib/Drupal/Core/Config/Schema/Property.php b/core/lib/Drupal/Core/Config/Schema/Property.php
index d7e4b60..d9ceacd 100644
--- a/core/lib/Drupal/Core/Config/Schema/Property.php
+++ b/core/lib/Drupal/Core/Config/Schema/Property.php
@@ -13,7 +13,7 @@
 class Property extends Element {
 
   /**
-   * Implements TypedDataInterface::validate().
+   * {@inheritdoc}
    */
   public function validate() {
     return isset($this->value);
diff --git a/core/lib/Drupal/Core/Entity/Entity.php b/core/lib/Drupal/Core/Entity/Entity.php
index 7712bf1..5741209 100644
--- a/core/lib/Drupal/Core/Entity/Entity.php
+++ b/core/lib/Drupal/Core/Entity/Entity.php
@@ -10,8 +10,6 @@
 use Drupal\Component\Uuid\Uuid;
 use Drupal\Core\Language\Language;
 use Drupal\Core\TypedData\TranslatableInterface;
-use Drupal\Core\TypedData\TypedDataInterface;
-use Drupal\user\UserInterface;
 use IteratorAggregate;
 use Drupal\Core\Session\AccountInterface;
 
@@ -425,62 +423,41 @@ public function getNGEntity() {
   }
 
   /**
-   * Implements \Drupal\Core\TypedData\TypedDataInterface::getType().
+   * {@inheritdoc}
    */
   public function getType() {
-    // @todo: Incorporate the entity type here by making entities proper
-    // typed data. See http://drupal.org/node/1868004.
-    return 'entity';
+    // @todo: This does not make much sense, so remove once TypedDataInterface
+    // is removed. See https://drupal.org/node/2002138.
+    if ($this->bundle() != $this->entityType()) {
+      return 'entity:' . $this->entityType() . ':' . $this->bundle();
+    }
+    return 'entity:' . $this->entityType();
   }
 
   /**
-   * Implements \Drupal\Core\TypedData\TypedDataInterface::getDefinition().
+   * {@inheritdoc}
    */
   public function getDefinition() {
+    // @todo: This does not make much sense, so remove once TypedDataInterface
+    // is removed. See https://drupal.org/node/2002138.
     return array(
       'type' => $this->getType()
     );
   }
 
   /**
-   * Implements \Drupal\Core\TypedData\TypedDataInterface::getValue().
-   */
-  public function getValue() {
-    // @todo: Implement by making entities proper typed data. See
-    // http://drupal.org/node/1868004.
-  }
-
-  /**
-   * Implements \Drupal\Core\TypedData\TypedDataInterface::setValue().
-   */
-  public function setValue($value, $notify = TRUE) {
-    // @todo: Implement by making entities proper typed data. See
-    // http://drupal.org/node/1868004.
-  }
-
-  /**
-   * Implements \Drupal\Core\TypedData\TypedDataInterface::getString().
-   */
-  public function getString() {
-    // @todo: Implement by making entities proper typed data. See
-    // http://drupal.org/node/1868004.
-  }
-
-  /**
-   * Implements \Drupal\Core\TypedData\TypedDataInterface::getConstraints().
+   * {@inheritdoc}
    */
   public function getConstraints() {
-    // @todo: Implement by making entities proper typed data. See
-    // http://drupal.org/node/1868004.
     return array();
   }
 
   /**
-   * Implements \Drupal\Core\TypedData\TypedDataInterface::validate().
+   * {@inheritdoc}
    */
   public function validate() {
-    // @todo: Implement by making entities proper typed data. See
-    // http://drupal.org/node/1868004.
+    // @todo: Add the typed data manager as proper dependency.
+    return \Drupal::typedData()->getValidator()->validate($this);
   }
 
   /**
@@ -500,37 +477,37 @@ public function onChange($property_name) {
   }
 
   /**
-   * Implements \Drupal\Core\TypedData\TypedDataInterface::getName().
+   * {@inheritdoc}
    */
   public function getName() {
     return NULL;
   }
 
   /**
-   * Implements \Drupal\Core\TypedData\TypedDataInterface::getRoot().
+   * {@inheritdoc}
    */
   public function getRoot() {
     return $this;
   }
 
   /**
-   * Implements \Drupal\Core\TypedData\TypedDataInterface::getPropertyPath().
+   * {@inheritdoc}
    */
   public function getPropertyPath() {
     return '';
   }
 
   /**
-   * Implements \Drupal\Core\TypedData\TypedDataInterface::getParent().
+   * {@inheritdoc}
    */
   public function getParent() {
     return NULL;
   }
 
   /**
-   * Implements \Drupal\Core\TypedData\TypedDataInterface::setContext().
+   * {@inheritdoc}
    */
-  public function setContext($name = NULL, TypedDataInterface $parent = NULL) {
+  public function setContext($name = NULL, $parent = NULL) {
     // As entities are always the root of the tree of typed data, we do not need
     // to set any parent or name.
   }
diff --git a/core/lib/Drupal/Core/Entity/EntityBCDecorator.php b/core/lib/Drupal/Core/Entity/EntityBCDecorator.php
index 52d3f6f..7af4a98 100644
--- a/core/lib/Drupal/Core/Entity/EntityBCDecorator.php
+++ b/core/lib/Drupal/Core/Entity/EntityBCDecorator.php
@@ -10,7 +10,6 @@
 use Drupal\Core\Language\Language;
 use IteratorAggregate;
 use Drupal\Core\Entity\EntityInterface;
-use Drupal\Core\TypedData\TypedDataInterface;
 use Drupal\Core\Session\AccountInterface;
 
 /**
@@ -184,6 +183,7 @@ public function __set($name, $value) {
     // out of sync. That way, the next field object instantiated by EntityNG
     // will hold the updated value.
     unset($this->decorated->fields[$name]);
+    $this->decorated->onChange($name);
   }
 
   /**
@@ -508,7 +508,7 @@ public function getParent() {
   /**
    * Forwards the call to the decorated entity.
    */
-  public function setContext($name = NULL, TypedDataInterface $parent = NULL) {
+  public function setContext($name = NULL, $parent = NULL) {
     $this->decorated->setContext($name, $parent);
   }
 
diff --git a/core/lib/Drupal/Core/Entity/EntityInterface.php b/core/lib/Drupal/Core/Entity/EntityInterface.php
index cdb4cd3..e965b8e 100644
--- a/core/lib/Drupal/Core/Entity/EntityInterface.php
+++ b/core/lib/Drupal/Core/Entity/EntityInterface.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\TypedData\AccessibleInterface;
 use Drupal\Core\TypedData\ComplexDataInterface;
+use Drupal\Core\TypedData\IdentifiableInterface;
 use Drupal\Core\TypedData\TranslatableInterface;
 
 /**
@@ -27,16 +28,7 @@
  * @see \Drupal\Core\TypedData\TypedDataManager
  * @see \Drupal\Core\Field\FieldInterface
  */
-interface EntityInterface extends ComplexDataInterface, AccessibleInterface, TranslatableInterface {
-
-  /**
-   * Returns the entity identifier (the entity's machine name or numeric ID).
-   *
-   * @return
-   *   The identifier of the entity, or NULL if the entity does not yet have
-   *   an identifier.
-   */
-  public function id();
+interface EntityInterface extends IdentifiableInterface, ComplexDataInterface, AccessibleInterface, TranslatableInterface {
 
   /**
    * Returns the entity UUID (Universally Unique Identifier).
diff --git a/core/lib/Drupal/Core/Entity/EntityNG.php b/core/lib/Drupal/Core/Entity/EntityNG.php
index 3d0c5c6..1bf4d88 100644
--- a/core/lib/Drupal/Core/Entity/EntityNG.php
+++ b/core/lib/Drupal/Core/Entity/EntityNG.php
@@ -9,7 +9,7 @@
 
 use Drupal\Core\Language\Language;
 use Drupal\Core\Session\AccountInterface;
-use Drupal\Core\TypedData\TypedDataInterface;
+use Drupal\Core\Entity\Field\FieldItemInterface;
 use ArrayIterator;
 use InvalidArgumentException;
 
@@ -458,7 +458,7 @@ protected function getDefaultLanguage() {
       }
       if (empty($this->language)) {
         // Make sure we return a proper language object.
-        $this->language = new Language(array('id' => Language::LANGCODE_NOT_SPECIFIED));
+        $this->language = new Language(array('id' => Language::LANGCODE_NOT_SPECIFIED, 'locked' => TRUE));
       }
     }
     return $this->language;
@@ -736,7 +736,7 @@ public function &__get($name) {
    */
   public function __set($name, $value) {
     // Support setting values via property objects.
-    if ($value instanceof TypedDataInterface && !$value instanceof EntityInterface) {
+    if ($value instanceof FieldItemInterface && !$value instanceof EntityInterface) {
       $value = $value->getValue();
     }
     // If this is an entity field, handle it accordingly. We first check whether
@@ -841,12 +841,4 @@ public function label($langcode = NULL) {
     return $label;
   }
 
-  /**
-   * {@inheritdoc}
-   */
-  public function validate() {
-    // @todo: Add the typed data manager as proper dependency.
-    return \Drupal::typedData()->getValidator()->validate($this);
-  }
-
 }
diff --git a/core/lib/Drupal/Core/Entity/Field/Field.php b/core/lib/Drupal/Core/Entity/Field/Field.php
index 3948ddf..ed0d93d 100644
--- a/core/lib/Drupal/Core/Entity/Field/Field.php
+++ b/core/lib/Drupal/Core/Entity/Field/Field.php
@@ -9,7 +9,6 @@
 
 use Drupal\Core\Entity\Field\FieldInterface;
 use Drupal\Core\Session\AccountInterface;
-use Drupal\Core\TypedData\TypedDataInterface;
 use Drupal\Core\TypedData\ItemList;
 
 /**
@@ -39,7 +38,7 @@ class Field extends ItemList implements FieldInterface {
   /**
    * Overrides TypedData::__construct().
    */
-  public function __construct(array $definition, $name = NULL, TypedDataInterface $parent = NULL) {
+  public function __construct(array $definition, $name = NULL, $parent = NULL) {
     parent::__construct($definition, $name, $parent);
     // Always initialize one empty item as most times a value for at least one
     // item will be present. That way prototypes created by
@@ -77,10 +76,6 @@ public function getValue($include_computed = FALSE) {
    * Overrides \Drupal\Core\TypedData\ItemList::setValue().
    */
   public function setValue($values, $notify = TRUE) {
-    // Notify the parent of any changes to be made.
-    if ($notify && isset($this->parent)) {
-      $this->parent->onChange($this->name);
-    }
     if (!isset($values) || $values === array()) {
       $this->list = $values;
     }
@@ -108,6 +103,10 @@ public function setValue($values, $notify = TRUE) {
         }
       }
     }
+    // Notify the parent of any changes.
+    if ($notify && isset($this->parent)) {
+      $this->parent->onChange($this->name);
+    }
   }
 
   /**
diff --git a/core/lib/Drupal/Core/Entity/Field/FieldItemBase.php b/core/lib/Drupal/Core/Entity/Field/FieldItemBase.php
index cb243d5..96e996e 100644
--- a/core/lib/Drupal/Core/Entity/Field/FieldItemBase.php
+++ b/core/lib/Drupal/Core/Entity/Field/FieldItemBase.php
@@ -9,7 +9,7 @@
 
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\TypedData\Plugin\DataType\Map;
-use Drupal\Core\TypedData\TypedDataInterface;
+use Drupal\Core\TypedData\PrimitiveInterface;
 use Drupal\user;
 
 /**
@@ -25,7 +25,7 @@
   /**
    * Overrides \Drupal\Core\TypedData\TypedData::__construct().
    */
-  public function __construct(array $definition, $name = NULL, TypedDataInterface $parent = NULL) {
+  public function __construct(array $definition, $name = NULL, $parent = NULL) {
     parent::__construct($definition, $name, $parent);
     // Initialize computed properties by default, such that they get cloned
     // with the whole item.
@@ -49,10 +49,6 @@ public function setValue($values, $notify = TRUE) {
       $keys = array_keys($this->getPropertyDefinitions());
       $values = array($keys[0] => $values);
     }
-    // Notify the parent of any changes to be made.
-    if ($notify && isset($this->parent)) {
-      $this->parent->onChange($this->name);
-    }
     $this->values = $values;
     // Update any existing property objects.
     foreach ($this->properties as $name => $property) {
@@ -63,6 +59,10 @@ public function setValue($values, $notify = TRUE) {
       $property->setValue($value, FALSE);
       unset($this->values[$name]);
     }
+    // Notify the parent of any changes.
+    if ($notify && isset($this->parent)) {
+      $this->parent->onChange($this->name);
+    }
   }
 
   /**
@@ -83,10 +83,6 @@ public function __get($name) {
    * {@inheritdoc}
    */
   public function set($property_name, $value, $notify = TRUE) {
-    // Notify the parent of any changes to be made.
-    if ($notify && isset($this->parent)) {
-      $this->parent->onChange($this->name);
-    }
     // For defined properties there is either a property object or a plain
     // value that needs to be updated.
     if (isset($this->properties[$property_name])) {
@@ -97,6 +93,10 @@ public function set($property_name, $value, $notify = TRUE) {
     else {
       $this->values[$property_name] = $value;
     }
+    // Directly notify ourselves.
+    if ($notify) {
+      $this->onChange($property_name);
+    }
   }
 
   /**
@@ -105,7 +105,7 @@ public function set($property_name, $value, $notify = TRUE) {
   public function __set($name, $value) {
     // Support setting values via property objects, but take care in as the
     // value of the 'entity' property is typed data also.
-    if ($value instanceof TypedDataInterface && !($value instanceof EntityInterface)) {
+    if ($value instanceof PrimitiveInterface && !($value instanceof EntityInterface)) {
       $value = $value->getValue();
     }
     $this->set($name, $value);
@@ -135,7 +135,9 @@ public function onChange($property_name) {
     }
     // Remove the plain value, such that any further __get() calls go via the
     // updated property object.
-    unset($this->values[$property_name]);
+    if (isset($this->properties[$property_name])) {
+      unset($this->values[$property_name]);
+    }
   }
 
   /**
diff --git a/core/lib/Drupal/Core/Entity/Plugin/DataType/Deriver/EntityDeriver.php b/core/lib/Drupal/Core/Entity/Plugin/DataType/Deriver/EntityDeriver.php
new file mode 100644
index 0000000..67ebea6
--- /dev/null
+++ b/core/lib/Drupal/Core/Entity/Plugin/DataType/Deriver/EntityDeriver.php
@@ -0,0 +1,67 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Entity\Plugin\DataType\Deriver\EntityDeriver.
+ */
+
+namespace Drupal\Core\Entity\Plugin\DataType\Deriver;
+
+use Drupal\Component\Plugin\Derivative\DerivativeInterface;
+
+/**
+ * Provides data type plugins for each existing entity type and bundle.
+ */
+class EntityDeriver implements DerivativeInterface {
+
+  /**
+   * List of derivative definitions.
+   *
+   * @var array
+   */
+  protected $derivatives = array();
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getDerivativeDefinition($derivative_id, array $base_plugin_definition) {
+    if (!empty($this->derivatives) && !empty($this->derivatives[$derivative_id])) {
+      return $this->derivatives[$derivative_id];
+    }
+    $this->getDerivativeDefinitions($base_plugin_definition);
+    if (isset($this->derivatives[$derivative_id])) {
+      return $this->derivatives[$derivative_id];
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getDerivativeDefinitions(array $base_plugin_definition) {
+    // Also keep the 'entity' defined as is.
+    $this->derivatives[''] = $base_plugin_definition;
+    // Add definitions for each entity type and bundle.
+    foreach (entity_get_info() as $entity_type => $info) {
+      $this->derivatives[$entity_type] = array(
+        'label' => $info['label'],
+        'class' => $info['class'],
+        'constraints' => array('EntityType' => $entity_type),
+      ) + $base_plugin_definition;
+
+      // Incorporate the bundles as entity:$entity_type:$bundle, if any.
+      foreach (entity_get_bundles($entity_type) as $bundle => $bundle_info) {
+        if ($bundle !== $entity_type) {
+          $this->derivatives[$entity_type . ':' . $bundle] = array(
+            'label' => $bundle_info['label'],
+            'class' => $info['class'],
+            'constraints' => array(
+              'EntityType' => $entity_type,
+              'Bundle' => $bundle,
+            ),
+          ) + $base_plugin_definition;
+        }
+      }
+    }
+    return $this->derivatives;
+  }
+}
diff --git a/core/lib/Drupal/Core/Entity/Plugin/DataType/Deriver/FieldItemDeriver.php b/core/lib/Drupal/Core/Entity/Plugin/DataType/Deriver/FieldItemDeriver.php
new file mode 100644
index 0000000..2a304df
--- /dev/null
+++ b/core/lib/Drupal/Core/Entity/Plugin/DataType/Deriver/FieldItemDeriver.php
@@ -0,0 +1,46 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Entity\Plugin\DataType\Deriver\FieldItemDeriver.
+ */
+
+namespace Drupal\Core\Entity\Plugin\DataType\Deriver;
+
+use Drupal\Component\Plugin\Derivative\DerivativeInterface;
+
+/**
+ * Provides data type plugins for each existing field type plugin.
+ */
+class FieldItemDeriver implements DerivativeInterface {
+
+  /**
+   * List of derivative definitions.
+   *
+   * @var array
+   */
+  protected $derivatives = array();
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getDerivativeDefinition($derivative_id, array $base_plugin_definition) {
+    if (!isset($this->derivatives)) {
+      $this->getDerivativeDefinitions($base_plugin_definition);
+    }
+    if (isset($this->derivatives[$derivative_id])) {
+      return $this->derivatives[$derivative_id];
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getDerivativeDefinitions(array $base_plugin_definition) {
+    foreach (\Drupal::service('plugin.manager.entity.field.field_type')->getDefinitions() as $plugin_id => $definition) {
+      $this->derivatives[$plugin_id] = $definition;
+    }
+    return $this->derivatives;
+  }
+
+}
diff --git a/core/lib/Drupal/Core/Entity/Plugin/DataType/Entity.php b/core/lib/Drupal/Core/Entity/Plugin/DataType/Entity.php
new file mode 100644
index 0000000..f1a61b0
--- /dev/null
+++ b/core/lib/Drupal/Core/Entity/Plugin/DataType/Entity.php
@@ -0,0 +1,28 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Entity\Plugin\DataType\Entity.
+ */
+
+namespace Drupal\Core\Entity\Plugin\DataType;
+
+use Drupal\Core\TypedData\Annotation\DataType;
+use Drupal\Core\Annotation\Translation;
+
+/**
+ * Defines the base plugin for deriving data types for entity types.
+ *
+ * Note that the class only register the plugin, and is actually never used.
+ * \Drupal\Core\Entity\Entity is available for use as base class.
+ *
+ * @DataType(
+ *   id = "entity",
+ *   label = @Translation("Entity"),
+ *   description = @Translation("All kind of entities, e.g. nodes, comments or users."),
+ *   derivative = "\Drupal\Core\Entity\Plugin\DataType\Deriver\EntityDeriver"
+ * )
+ */
+abstract class Entity {
+
+}
diff --git a/core/lib/Drupal/Core/Entity/Plugin/DataType/EntityReference.php b/core/lib/Drupal/Core/Entity/Plugin/DataType/EntityReference.php
new file mode 100644
index 0000000..1f85cc3
--- /dev/null
+++ b/core/lib/Drupal/Core/Entity/Plugin/DataType/EntityReference.php
@@ -0,0 +1,128 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Entity\Plugin\DataType\EntityReference.
+ */
+
+namespace Drupal\Core\Entity\Plugin\DataType;
+
+use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\TypedData\Annotation\DataType;
+use Drupal\Core\Annotation\Translation;
+use Drupal\Core\TypedData\DataReferenceBase;
+
+/**
+ * Defines an 'entity_reference' data type.
+ *
+ * This serves as 'entity' property of entity reference field items and gets
+ * its value set from the parent, i.e. LanguageItem.
+ *
+ * The plain value of this reference is the entity object, i.e. an instance of
+ * \Drupal\Core\Entity\EntityInterface. For setting the value the entity object
+ * or the entity ID may be passed, whereas passing the ID is only supported if
+ * an 'entity type' constraint is specified.
+ *
+ * Some supported constraints (below the definition's 'constraints' key) are:
+ *  - EntityType: The entity type. Required.
+ *  - Bundle: (optional) The bundle or an array of possible bundles.
+ *
+ * @DataType(
+ *   id = "entity_reference",
+ *   label = @Translation("Entity reference")
+ * )
+ */
+class EntityReference extends DataReferenceBase {
+
+  /**
+   * The entity ID.
+   *
+   * @var integer|string
+   */
+  protected $id;
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getTargetDefinition() {
+    $definition = array(
+      'type' => 'entity',
+    );
+    if (isset($this->definition['constraints']['EntityType'])) {
+      $definition['type'] .= ':' . $this->definition['constraints']['EntityType'];
+    }
+    if (isset($this->definition['constraints']['Bundle']) && is_string($this->definition['constraints']['Bundle'])) {
+      $definition['type'] .= ':' . $this->definition['constraints']['Bundle'];
+    }
+    return $definition;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getTarget() {
+    if (!isset($this->target) && isset($this->id)) {
+      // If we have a valid reference, return the entity object which is typed
+      // data itself.
+      $this->target = entity_load($this->definition['constraints']['EntityType'], $this->id);
+    }
+    return $this->target;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getTargetIdentifier() {
+    if (isset($this->id)) {
+      return $this->id;
+    }
+    elseif ($entity = $this->getValue()) {
+      return $entity->id();
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getValue() {
+    // Entities are already typed data, so just return that.
+    return $this->getTarget();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setValue($value, $notify = TRUE) {
+    unset($this->target);
+    unset($this->id);
+
+    // Both the entity ID and the entity object may be passed as value.
+    if (!isset($value) || $value instanceof EntityInterface) {
+      // Enusre we set no BCEntity.
+      if (isset($value)) {
+        $value = $value->getNGEntity();
+      }
+      $this->target = $value;
+    }
+    elseif (!is_scalar($value) || empty($this->definition['constraints']['EntityType'])) {
+      throw new \InvalidArgumentException('Value is not a valid entity.');
+    }
+    else {
+      $this->id = $value;
+    }
+    // Notify the parent of any changes.
+    if ($notify && isset($this->parent)) {
+      $this->parent->onChange($this->name);
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getString() {
+    if ($entity = $this->getValue()) {
+      return $entity->label();
+    }
+    return '';
+  }
+}
diff --git a/core/lib/Drupal/Core/Entity/Plugin/DataType/EntityReferenceItem.php b/core/lib/Drupal/Core/Entity/Plugin/DataType/EntityReferenceItem.php
index 7f756ad..ae84ceb 100644
--- a/core/lib/Drupal/Core/Entity/Plugin/DataType/EntityReferenceItem.php
+++ b/core/lib/Drupal/Core/Entity/Plugin/DataType/EntityReferenceItem.php
@@ -10,13 +10,15 @@
 use Drupal\Core\TypedData\Annotation\DataType;
 use Drupal\Core\Annotation\Translation;
 use Drupal\Core\Entity\Field\FieldItemBase;
-use Drupal\Core\TypedData\TypedDataInterface;
 
 /**
- * Defines the 'entity_reference' entity field item.
+ * Defines the 'entity_reference_item' entity field item.
  *
- * Required settings (below the definition's 'settings' key) are:
- *  - target_type: The entity type to reference.
+ * Supported settings (below the definition's 'settings' key) are:
+ * - target_type: The entity type to reference. Required.
+ * - target_bundle: (optional): If set, restricts the entity bundles which may
+ *   may be referenced. May be set to an single bundle, or to an array of
+ *   allowed bundles.
  *
  * @DataType(
  *   id = "entity_reference_field",
@@ -40,11 +42,12 @@ class EntityReferenceItem extends FieldItemBase {
    * Implements \Drupal\Core\TypedData\ComplexDataInterface::getPropertyDefinitions().
    */
   public function getPropertyDefinitions() {
-    // Definitions vary by entity type, so key them by entity type.
-    $target_type = $this->definition['settings']['target_type'];
+    // Definitions vary by entity type and bundle, so key them accordingly.
+    $key = $this->definition['settings']['target_type'] . ':';
+    $key .= isset($this->definition['settings']['target_bundle']) ? $this->definition['settings']['target_bundle'] : '';
 
-    if (!isset(self::$propertyDefinitions[$target_type])) {
-      static::$propertyDefinitions[$target_type]['target_id'] = array(
+    if (!isset(static::$propertyDefinitions[$key])) {
+      static::$propertyDefinitions[$key]['target_id'] = array(
         // @todo: Lookup the entity type's ID data type and use it here.
         'type' => 'integer',
         'label' => t('Entity ID'),
@@ -52,20 +55,22 @@ public function getPropertyDefinitions() {
           'Range' => array('min' => 0),
         ),
       );
-      static::$propertyDefinitions[$target_type]['entity'] = array(
-        'type' => 'entity',
+      static::$propertyDefinitions[$key]['entity'] = array(
+        'type' => 'entity_reference',
         'constraints' => array(
-          'EntityType' => $target_type,
+          'EntityType' => $this->definition['settings']['target_type'],
         ),
         'label' => t('Entity'),
         'description' => t('The referenced entity'),
         // The entity object is computed out of the entity ID.
         'computed' => TRUE,
         'read-only' => FALSE,
-        'settings' => array('id source' => 'target_id'),
       );
+      if (isset($this->definition['settings']['target_bundle'])) {
+        static::$propertyDefinitions[$key]['entity']['constraints']['Bundle'] = $this->definition['settings']['target_bundle'];
+      }
     }
-    return static::$propertyDefinitions[$target_type];
+    return static::$propertyDefinitions[$key];
   }
 
   /**
@@ -96,12 +101,14 @@ public function __isset($property_name) {
    * Overrides \Drupal\Core\Entity\Field\FieldItemBase::get().
    */
   public function setValue($values, $notify = TRUE) {
-    // Treat the values as value of the entity property, if no array is
-    // given as this handles entity IDs and objects.
     if (isset($values) && !is_array($values)) {
-      // Directly update the property instead of invoking the parent, so that
-      // the entity property can take care of updating the ID property.
+      // Directly update the property instead of invoking the parent, so it can
+      // handle objects and IDs.
       $this->properties['entity']->setValue($values, $notify);
+      // If notify was FALSE, ensure the target_id property gets synched.
+      if (!$notify) {
+        $this->set('target_id', $this->properties['entity']->getTargetIdentifier(), FALSE);
+      }
     }
     else {
       // Make sure that the 'entity' property gets set as 'target_id'.
@@ -111,4 +118,18 @@ public function setValue($values, $notify = TRUE) {
       parent::setValue($values, $notify);
     }
   }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function onChange($property_name) {
+    // Make sure that the target ID and the target property stay in sync.
+    if ($property_name == 'target_id') {
+      $this->properties['entity']->setValue($this->target_id, FALSE);
+    }
+    elseif ($property_name == 'entity') {
+      $this->set('target_id', $this->properties['entity']->getTargetIdentifier(), FALSE);
+    }
+    parent::onChange($property_name);
+  }
 }
diff --git a/core/lib/Drupal/Core/Entity/Plugin/DataType/EntityWrapper.php b/core/lib/Drupal/Core/Entity/Plugin/DataType/EntityWrapper.php
deleted file mode 100644
index e2561a9..0000000
--- a/core/lib/Drupal/Core/Entity/Plugin/DataType/EntityWrapper.php
+++ /dev/null
@@ -1,227 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\Core\Entity\Plugin\DataType\EntityWrapper.
- */
-
-namespace Drupal\Core\Entity\Plugin\DataType;
-
-use Drupal\Core\TypedData\Annotation\DataType;
-use Drupal\Core\Annotation\Translation;
-use Drupal\Core\Entity\EntityInterface;
-use Drupal\Core\TypedData\ComplexDataInterface;
-use Drupal\Core\TypedData\TypedData;
-use Drupal\Core\TypedData\TypedDataInterface;
-use ArrayIterator;
-use IteratorAggregate;
-use InvalidArgumentException;
-
-/**
- * Defines an 'entity' data type, e.g. the computed 'entity' property of entity references.
- *
- * This object wraps the regular entity object and implements the
- * ComplexDataInterface by forwarding most of its methods to the wrapped entity
- * (if set).
- *
- * The plain value of this wrapper is the entity object, i.e. an instance of
- * Drupal\Core\Entity\EntityInterface. For setting the value the entity object
- * or the entity ID may be passed, whereas passing the ID is only supported if
- * an 'entity type' constraint is specified.
- *
- * Supported constraints (below the definition's 'constraints' key) are:
- *  - EntityType: The entity type.
- *  - Bundle: The bundle or an array of possible bundles.
- *
- * Supported settings (below the definition's 'settings' key) are:
- *  - id source: If used as computed property, the ID property used to load
- *    the entity object.
- *
- * @DataType(
- *   id = "entity",
- *   label = @Translation("Entity"),
- *   description = @Translation("All kind of entities, e.g. nodes, comments or users.")
- * )
- */
-class EntityWrapper extends TypedData implements IteratorAggregate, ComplexDataInterface {
-
-  /**
-   * The referenced entity type.
-   *
-   * @var string
-   */
-  protected $entityType;
-
-  /**
-   * The entity ID if no 'id source' is used.
-   *
-   * @var string
-   */
-  protected $id;
-
-  /**
-   * If set, a new entity to create and reference.
-   *
-   * @var \Drupal\Core\Entity\EntityInterface
-   */
-  protected $newEntity;
-
-  /**
-   * Overrides TypedData::__construct().
-   */
-  public function __construct(array $definition, $name = NULL, TypedDataInterface $parent = NULL) {
-    parent::__construct($definition, $name, $parent);
-    $this->entityType = isset($this->definition['constraints']['EntityType']) ? $this->definition['constraints']['EntityType'] : NULL;
-  }
-
-  /**
-   * Overrides \Drupal\Core\TypedData\TypedData::getValue().
-   */
-  public function getValue() {
-    if (isset($this->newEntity)) {
-      return $this->newEntity;
-    }
-    if (!empty($this->definition['settings']['id source'])) {
-      $this->id = $this->parent->__get($this->definition['settings']['id source']);
-    }
-    return $this->id ? entity_load($this->entityType, $this->id) : NULL;
-  }
-
-  /**
-   * Overrides \Drupal\Core\TypedData\TypedData::setValue().
-   *
-   * Both the entity ID and the entity object may be passed as value.
-   */
-  public function setValue($value, $notify = TRUE) {
-    // Support passing in the entity object. If it's not yet saved we have
-    // to store the whole entity such that it could be saved later on.
-    if ($value instanceof EntityInterface && $value->isNew()) {
-      $this->newEntity = $value;
-      $this->entityType = $value->entityType();
-      $value = 0;
-    }
-    elseif ($value instanceof EntityInterface) {
-      $this->entityType = $value->entityType();
-      $value = $value->id();
-      unset($this->newEntity);
-    }
-    elseif (isset($value) && !(is_scalar($value) && !empty($this->definition['constraints']['EntityType']))) {
-      throw new InvalidArgumentException('Value is not a valid entity.');
-    }
-    // Update the 'id source' property, if given.
-    if (!empty($this->definition['settings']['id source'])) {
-      $this->parent->__set($this->definition['settings']['id source'], $value, $notify);
-    }
-    else {
-      // Notify the parent of any changes to be made.
-      if ($notify && isset($this->parent)) {
-        $this->parent->onChange($this->name);
-      }
-      $this->id = $value;
-    }
-  }
-
-  /**
-   * Overrides \Drupal\Core\TypedData\TypedData::getString().
-   */
-  public function getString() {
-    if ($entity = $this->getValue()) {
-      return $entity->label();
-    }
-    return '';
-  }
-
-  /**
-   * Implements \IteratorAggregate::getIterator().
-   */
-  public function getIterator() {
-    if ($entity = $this->getValue()) {
-      return $entity->getIterator();
-    }
-    return new ArrayIterator(array());
-  }
-
-  /**
-   * Implements \Drupal\Core\TypedData\ComplexDataInterface::get().
-   */
-  public function get($property_name) {
-    // @todo: Allow navigating through the tree without data as well.
-    if ($entity = $this->getValue()) {
-      return $entity->get($property_name);
-    }
-  }
-
-  /**
-   * Implements \Drupal\Core\TypedData\ComplexDataInterface::set().
-   */
-  public function set($property_name, $value, $notify = TRUE) {
-    $this->get($property_name)->setValue($value, FALSE);
-  }
-
-  /**
-   * Implements \Drupal\Core\TypedData\ComplexDataInterface::getProperties().
-   */
-  public function getProperties($include_computed = FALSE) {
-    if ($entity = $this->getValue()) {
-      return $entity->getProperties($include_computed);
-    }
-    return array();
-  }
-
-  /**
-   * Implements \Drupal\Core\TypedData\ComplexDataInterface::getPropertyDefinition().
-   */
-  public function getPropertyDefinition($name) {
-    $definitions = $this->getPropertyDefinitions();
-    if (isset($definitions[$name])) {
-      return $definitions[$name];
-    }
-    else {
-      return FALSE;
-    }
-  }
-
-  /**
-   * Implements \Drupal\Core\TypedData\ComplexDataInterface::getPropertyDefinitions().
-   */
-  public function getPropertyDefinitions() {
-    // @todo: Support getting definitions if multiple bundles are specified.
-    return \Drupal::entityManager()->getFieldDefinitionsByConstraints($this->entityType, $this->definition['constraints']);
-  }
-
-  /**
-   * Implements \Drupal\Core\TypedData\ComplexDataInterface::getPropertyValues().
-   */
-  public function getPropertyValues() {
-    if ($entity = $this->getValue()) {
-      return $entity->getPropertyValues();
-    }
-    return array();
-  }
-
-  /**
-   * Implements \Drupal\Core\TypedData\ComplexDataInterface::setPropertyValues().
-   */
-  public function setPropertyValues($values) {
-    if ($entity = $this->getValue()) {
-      $entity->setPropertyValues($values);
-    }
-  }
-
-  /**
-   * Implements \Drupal\Core\TypedData\ComplexDataInterface::isEmpty().
-   */
-  public function isEmpty() {
-    return !$this->getValue();
-  }
-
-  /**
-   * Implements \Drupal\Core\TypedData\ComplexDataInterface::onChange().
-   */
-  public function onChange($property_name) {
-    // Notify the parent of changes.
-    if (isset($this->parent)) {
-      $this->parent->onChange($this->name);
-    }
-  }
-}
diff --git a/core/lib/Drupal/Core/Entity/Plugin/DataType/FieldDataTypeDerivative.php b/core/lib/Drupal/Core/Entity/Plugin/DataType/FieldDataTypeDerivative.php
deleted file mode 100644
index 346b656..0000000
--- a/core/lib/Drupal/Core/Entity/Plugin/DataType/FieldDataTypeDerivative.php
+++ /dev/null
@@ -1,46 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\Core\Entity\Plugin\DataType\FieldDataTypeDerivative.
- */
-
-namespace Drupal\Core\Entity\Plugin\DataType;
-
-use Drupal\Component\Plugin\Derivative\DerivativeInterface;
-
-/**
- * Provides data type plugins for each existing field type plugin.
- */
-class FieldDataTypeDerivative implements DerivativeInterface {
-
-  /**
-   * List of derivative definitions.
-   *
-   * @var array
-   */
-  protected $derivatives = array();
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getDerivativeDefinition($derivative_id, array $base_plugin_definition) {
-    if (!isset($this->derivatives)) {
-      $this->getDerivativeDefinitions($base_plugin_definition);
-    }
-    if (isset($this->derivatives[$derivative_id])) {
-      return $this->derivatives[$derivative_id];
-    }
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getDerivativeDefinitions(array $base_plugin_definition) {
-    foreach (\Drupal::service('plugin.manager.entity.field.field_type')->getDefinitions() as $plugin_id => $definition) {
-      $this->derivatives[$plugin_id] = $definition;
-    }
-    return $this->derivatives;
-  }
-
-}
diff --git a/core/lib/Drupal/Core/Entity/Plugin/DataType/FieldItem.php b/core/lib/Drupal/Core/Entity/Plugin/DataType/FieldItem.php
index 73309d9..71fa264 100644
--- a/core/lib/Drupal/Core/Entity/Plugin/DataType/FieldItem.php
+++ b/core/lib/Drupal/Core/Entity/Plugin/DataType/FieldItem.php
@@ -9,18 +9,20 @@
 
 use Drupal\Core\TypedData\Annotation\DataType;
 use Drupal\Core\Annotation\Translation;
-use Drupal\Component\Plugin\PluginBase;
 
 /**
- * Defines the base plugin definition for field type typed data types.
+ * Defines the base plugin for deriving data types for field types.
+ *
+ * Note that the class only register the plugin, and is actually never used.
+ * \Drupal\Core\Entity\Field\FieldItemBase is available for use as base class.
  *
  * @DataType(
  *   id = "field_item",
  *   label = @Translation("Field item"),
  *   list_class = "\Drupal\Core\Entity\Field\Field",
- *   derivative = "Drupal\Core\Entity\Plugin\DataType\FieldDataTypeDerivative"
+ *   derivative = "Drupal\Core\Entity\Plugin\DataType\Deriver\FieldItemDeriver"
  * )
  */
-class FieldItem extends PluginBase {
+abstract class FieldItem {
 
 }
diff --git a/core/lib/Drupal/Core/Entity/Plugin/DataType/LanguageItem.php b/core/lib/Drupal/Core/Entity/Plugin/DataType/LanguageItem.php
index 5338556..68526f5 100644
--- a/core/lib/Drupal/Core/Entity/Plugin/DataType/LanguageItem.php
+++ b/core/lib/Drupal/Core/Entity/Plugin/DataType/LanguageItem.php
@@ -42,19 +42,18 @@ class LanguageItem extends FieldItemBase {
    * Implements \Drupal\Core\TypedData\ComplexDataInterface::getPropertyDefinitions().
    */
   public function getPropertyDefinitions() {
-
     if (!isset(static::$propertyDefinitions)) {
       static::$propertyDefinitions['value'] = array(
         'type' => 'string',
         'label' => t('Language code'),
       );
       static::$propertyDefinitions['language'] = array(
-        'type' => 'language',
+        'type' => 'language_reference',
         'label' => t('Language object'),
+        'description' => t('The referenced language'),
         // The language object is retrieved via the language code.
         'computed' => TRUE,
         'read-only' => FALSE,
-        'settings' => array('langcode source' => 'value'),
       );
     }
     return static::$propertyDefinitions;
@@ -71,6 +70,10 @@ public function setValue($values, $notify = TRUE) {
       // the language property can take care of updating the language code
       // property.
       $this->properties['language']->setValue($values, $notify);
+      // If notify was FALSE, ensure the value property gets synched.
+      if (!$notify) {
+        $this->set('value', $this->properties['language']->getTargetIdentifier(), FALSE);
+      }
     }
     else {
       // Make sure that the 'language' property gets set as 'value'.
@@ -89,4 +92,18 @@ public function applyDefaultValue($notify = TRUE) {
     $this->setValue(array('value' => Language::LANGCODE_NOT_SPECIFIED), $notify);
     return $this;
   }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function onChange($property_name) {
+    // Make sure that the value and the language property stay in sync.
+    if ($property_name == 'value') {
+      $this->properties['language']->setValue($this->value, FALSE);
+    }
+    elseif ($property_name == 'language') {
+      $this->set('value', $this->properties['language']->getTargetIdentifier(), FALSE);
+    }
+    parent::onChange($property_name);
+  }
 }
diff --git a/core/lib/Drupal/Core/Entity/Plugin/DataType/LanguageReference.php b/core/lib/Drupal/Core/Entity/Plugin/DataType/LanguageReference.php
new file mode 100644
index 0000000..8d143a7
--- /dev/null
+++ b/core/lib/Drupal/Core/Entity/Plugin/DataType/LanguageReference.php
@@ -0,0 +1,39 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Entity\Plugin\DataType\LanguageReference.
+ */
+
+namespace Drupal\Core\Entity\Plugin\DataType;
+
+use Drupal\Core\TypedData\DataReferenceBase;
+use Drupal\Core\TypedData\Annotation\DataType;
+use Drupal\Core\Annotation\Translation;
+
+/**
+ * Defines the 'language_reference' data type.
+ *
+ * This serves as 'language' property of entity reference field items and gets
+ * its value set from the parent, i.e. LanguageItem.
+ *
+ * The plain value is the language object, i.e. an instance of
+ * \Drupal\Core\Language\Language. For setting the value the language object or
+ * the language code as string may be passed.
+ *
+ * @DataType(
+ *   id = "language_reference",
+ *   label = @Translation("Language reference")
+ * )
+ */
+class LanguageReference extends DataReferenceBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getTargetDefinition() {
+    return array(
+      'type' => 'language',
+    );
+  }
+}
diff --git a/core/lib/Drupal/Core/Entity/Query/Sql/Tables.php b/core/lib/Drupal/Core/Entity/Query/Sql/Tables.php
index f346129..2f7156a 100644
--- a/core/lib/Drupal/Core/Entity/Query/Sql/Tables.php
+++ b/core/lib/Drupal/Core/Entity/Query/Sql/Tables.php
@@ -8,6 +8,7 @@
 namespace Drupal\Core\Entity\Query\Sql;
 
 use Drupal\Core\Database\Query\SelectInterface;
+use Drupal\Core\Entity\Plugin\DataType\EntityReference;
 use Drupal\Core\Entity\Query\QueryException;
 use Drupal\field\Plugin\Core\Entity\Field;
 
@@ -140,13 +141,12 @@ function addField($field, $type, $langcode) {
             $propertyDefinitions = $entity->{$field['field_name']}->getPropertyDefinitions();
 
             // If the column is not yet known, ie. the
-            // $node->field_image->entity case then use the id source as the
-            // column.
-            if (!$column && isset($propertyDefinitions[$relationship_specifier]['settings']['id source'])) {
-              // If this is a valid relationship, use the id source.
-              // Otherwise, the code executing the relationship will throw an
-              // exception anyways so no need to do it here.
-              $column = $propertyDefinitions[$relationship_specifier]['settings']['id source'];
+            // $node->field_image->entity case then use first property as
+            // column, i.e. target_id or fid.
+            // Otherwise, the code executing the relationship will throw an
+            // exception anyways so no need to do it here.
+            if (!$column && isset($propertyDefinitions[$relationship_specifier]) && $entity->{$field['field_name']}->get('entity') instanceof EntityReference) {
+              $column = current(array_keys($propertyDefinitions));
             }
             // Prepare the next index prefix.
             $next_index_prefix = "$relationship_specifier.$column";
@@ -193,7 +193,7 @@ function addField($field, $type, $langcode) {
           $next_index_prefix = $relationship_specifier;
         }
         // Check for a valid relationship.
-        if (isset($propertyDefinitions[$relationship_specifier]['constraints']['EntityType']) && isset($propertyDefinitions[$relationship_specifier]['settings']['id source'])) {
+        if (isset($propertyDefinitions[$relationship_specifier]) && $entity->{$specifier}->get('entity') instanceof EntityReference) {
           // If it is, use the entity type.
           $entity_type = $propertyDefinitions[$relationship_specifier]['constraints']['EntityType'];
           $entity_info = entity_get_info($entity_type);
diff --git a/core/lib/Drupal/Core/Plugin/Context/Context.php b/core/lib/Drupal/Core/Plugin/Context/Context.php
index fbdf658..8d67080 100644
--- a/core/lib/Drupal/Core/Plugin/Context/Context.php
+++ b/core/lib/Drupal/Core/Plugin/Context/Context.php
@@ -11,7 +11,7 @@
 use Drupal\Core\Entity\Plugin\DataType\EntityWrapper;
 use Drupal\Core\TypedData\ComplexDataInterface;
 use Drupal\Core\TypedData\ListInterface;
-use Drupal\Core\TypedData\TypedDataInterface;
+use Drupal\Core\TypedData\PrimitiveInterface;
 use Drupal\Core\Validation\DrupalTranslator;
 use Symfony\Component\Validator\Validation;
 
@@ -37,7 +37,7 @@ public function getContextValue() {
       $is_complex = $typed_value[0] instanceof ComplexDataInterface;
     }
     // @todo We won't need the getType == entity check once #1868004 lands.
-    if ($typed_value instanceof TypedDataInterface && (!$is_complex || $typed_value instanceof EntityWrapper)) {
+    if ($typed_value instanceof PrimitiveInterface && (!$is_complex || $typed_value instanceof EntityWrapper)) {
       return $typed_value->getValue();
     }
     return $typed_value;
@@ -48,7 +48,7 @@ public function getContextValue() {
    */
   public function setContextValue($value) {
     // Make sure the value set is a typed data object.
-    if (!empty($this->contextDefinition['type']) && !$value instanceof TypedDataInterface) {
+    if (!empty($this->contextDefinition['type']) && !\Drupal::typedData()->isTypedData($value)) {
       $value = \Drupal::typedData()->create($this->contextDefinition, $value);
     }
     parent::setContextValue($value);
diff --git a/core/lib/Drupal/Core/TypedData/ComplexDataInterface.php b/core/lib/Drupal/Core/TypedData/ComplexDataInterface.php
index 595064e..7cb6037 100644
--- a/core/lib/Drupal/Core/TypedData/ComplexDataInterface.php
+++ b/core/lib/Drupal/Core/TypedData/ComplexDataInterface.php
@@ -21,7 +21,7 @@
  * When implementing this interface which extends Traversable, make sure to list
  * IteratorAggregate or Iterator before this interface in the implements clause.
  */
-interface ComplexDataInterface extends Traversable, TypedDataInterface  {
+interface ComplexDataInterface extends Traversable, TypedDataInterface, ContextAwareInterface  {
 
   /**
    * Gets a property object.
@@ -128,7 +128,7 @@ public function isEmpty();
   /**
    * React to changes to a child property.
    *
-   * Note that this is invoked before any changes are applied.
+   * Note that this is invoked after any changes have been applied.
    *
    * @param $property_name
    *   The name of the property which is changed.
diff --git a/core/lib/Drupal/Core/TypedData/ContextAwareInterface.php b/core/lib/Drupal/Core/TypedData/ContextAwareInterface.php
new file mode 100644
index 0000000..dc835c0
--- /dev/null
+++ b/core/lib/Drupal/Core/TypedData/ContextAwareInterface.php
@@ -0,0 +1,72 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\TypedData\ContextAwareInterface.
+ */
+
+namespace Drupal\Core\TypedData;
+
+/**
+ * Interface for typed data objects that are aware of its own property name and
+ * parent context.
+ */
+interface ContextAwareInterface {
+
+  /**
+   * Returns the name of a property or item.
+   *
+   * @return string
+   *   If the data is a property of some complex data, the name of the property.
+   *   If the data is an item of a list, the name is the numeric position of the
+   *   item in the list, starting with 0. Otherwise, NULL is returned.
+   */
+  public function getName();
+
+  /**
+   * Returns the parent data structure; i.e. either complex data or a list.
+   *
+   * @return \Drupal\Core\TypedData\ComplexDataInterface|\Drupal\Core\TypedData\ListInterface
+   *   The parent data structure, either complex data or a list; or NULL if this
+   *   is the root of the typed data tree.
+   */
+  public function getParent();
+
+  /**
+   * Returns the root of the typed data tree.
+   *
+   * Returns the root data for a tree of typed data objects; e.g. for an entity
+   * field item the root of the tree is its parent entity object.
+   *
+   * @return \Drupal\Core\TypedData\ComplexDataInterface|\Drupal\Core\TypedData\ListInterface
+   *   The root data structure, either complex data or a list.
+   */
+  public function getRoot();
+
+  /**
+   * Returns the property path of the data.
+   *
+   * The trail of property names relative to the root of the typed data tree,
+   * separated by dots; e.g. 'field_text.0.format'.
+   *
+   * @return string
+   *   The property path relative to the root of the typed tree, or an empty
+   *   string if this is the root.
+   */
+  public function getPropertyPath();
+
+  /**
+   * Sets the context of a property or item via a context aware parent.
+   *
+   * This method is supposed to be called by the factory only.
+   *
+   * @param string $name
+   *   (optional) The name of the property or the delta of the list item,
+   *   or NULL if it is the root of a typed data tree. Defaults to NULL.
+   * @param \Drupal\Core\TypedData\TypedDataInterface $parent
+   *   (optional) The parent object of the data property, or NULL if it is the
+   *   root of a typed data tree. Defaults to NULL.
+   */
+  public function setContext($name = NULL, $parent = NULL);
+
+}
diff --git a/core/lib/Drupal/Core/TypedData/DataDefinitionException.php b/core/lib/Drupal/Core/TypedData/DataDefinitionException.php
new file mode 100644
index 0000000..2a23315
--- /dev/null
+++ b/core/lib/Drupal/Core/TypedData/DataDefinitionException.php
@@ -0,0 +1,15 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\TypedData\MissingContextException.
+ */
+
+namespace Drupal\Core\TypedData;
+
+/**
+ * Exception thrown when a data definition lacks required information.
+ */
+class DataDefinitionException extends \Exception {
+
+}
diff --git a/core/lib/Drupal/Core/TypedData/DataReferenceBase.php b/core/lib/Drupal/Core/TypedData/DataReferenceBase.php
new file mode 100644
index 0000000..8e67a24
--- /dev/null
+++ b/core/lib/Drupal/Core/TypedData/DataReferenceBase.php
@@ -0,0 +1,67 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\TypedData\DataReferenceBase.
+ */
+
+namespace Drupal\Core\TypedData;
+
+/**
+ * Base class for typed data references.
+ *
+ * Implementing classes have to implement at least
+ * \Drupal\Core\TypedData\DataReferenceInterface::getTargetDefinition() and
+ * \Drupal\Core\TypedData\DataReferenceInterface::getTargetIdentifier().
+ */
+abstract class DataReferenceBase extends TypedData implements DataReferenceInterface  {
+
+  /**
+   * The referenced data.
+   *
+   * @var \Drupal\Core\TypedData\TypedDataInterface
+   */
+  protected $target;
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getTarget() {
+    return $this->target;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getValue() {
+    if ($target = $this->getTarget()) {
+      return $target->getValue();
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setValue($value, $notify = TRUE) {
+    $this->target = \Drupal::typedData()->create($this->getTargetDefinition(), $value);
+    // Notify the parent of any changes.
+    if ($notify && isset($this->parent)) {
+      $this->parent->onChange($this->name);
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getString() {
+    return (string) $this->getType() . ':' . $this->getTargetIdentifier();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getTargetIdentifier() {
+    $target = $this->getTarget();
+    return isset($target) ? $target->id() : NULL;
+  }
+}
diff --git a/core/lib/Drupal/Core/TypedData/DataReferenceInterface.php b/core/lib/Drupal/Core/TypedData/DataReferenceInterface.php
new file mode 100644
index 0000000..501f9d2
--- /dev/null
+++ b/core/lib/Drupal/Core/TypedData/DataReferenceInterface.php
@@ -0,0 +1,38 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\TypedData\DataReferenceInterface.
+ */
+
+namespace Drupal\Core\TypedData;
+
+/**
+ * Interface for typed data references.
+ */
+interface DataReferenceInterface  {
+
+  /**
+   * Gets the data definition of the referenced data.
+   *
+   * @return array
+   *   The data definition of the referenced data.
+   */
+  public function getTargetDefinition();
+
+  /**
+   * Gets the referenced data.
+   *
+   * @return \Drupal\Core\TypedData\TypedDataInterface|null
+   *   The referenced typed data object, or NULL if the reference is unset.
+   */
+  public function getTarget();
+
+  /**
+   * Gets the identifier of the referenced data.
+   *
+   * @return int|string|null
+   *   The identifier of the referenced data, or NULL if the reference is unset.
+   */
+  public function getTargetIdentifier();
+}
diff --git a/core/lib/Drupal/Core/TypedData/DefaultableInterface.php b/core/lib/Drupal/Core/TypedData/DefaultableInterface.php
new file mode 100644
index 0000000..99e3783
--- /dev/null
+++ b/core/lib/Drupal/Core/TypedData/DefaultableInterface.php
@@ -0,0 +1,28 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\TypedData\DefaultableInterface.
+ */
+
+namespace Drupal\Core\TypedData;
+
+/**
+ * Interface for typed data that can have a default value.
+ */
+interface DefaultableInterface {
+
+  /**
+   * Applies the default value.
+   *
+   * @param bool $notify
+   *   (optional) Whether to notify the parent object of the change. Defaults to
+   *   TRUE. If a property is updated from a parent object, set it to FALSE to
+   *   avoid being notified again.
+   *
+   * @return \Drupal\Core\TypedData\TypedDataInterface
+   *   Returns itself to allow for chaining.
+   */
+  public function applyDefaultValue($notify = TRUE);
+
+}
diff --git a/core/lib/Drupal/Core/TypedData/IdentifiableInterface.php b/core/lib/Drupal/Core/TypedData/IdentifiableInterface.php
new file mode 100644
index 0000000..09f8c92
--- /dev/null
+++ b/core/lib/Drupal/Core/TypedData/IdentifiableInterface.php
@@ -0,0 +1,22 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\TypedData\IdentifiableInterface.
+ */
+
+namespace Drupal\Core\TypedData;
+
+/**
+ * Interface for identifiable typed data.
+ */
+interface IdentifiableInterface {
+
+  /**
+   * Returns the identifier.
+   *
+   * @return string|int|null
+   *   The object identifier, or NULL if the object does not yet have an identifier.
+   */
+  public function id();
+}
diff --git a/core/lib/Drupal/Core/TypedData/ItemList.php b/core/lib/Drupal/Core/TypedData/ItemList.php
index ee69432..cccb576 100644
--- a/core/lib/Drupal/Core/TypedData/ItemList.php
+++ b/core/lib/Drupal/Core/TypedData/ItemList.php
@@ -42,10 +42,6 @@ public function getValue() {
    *   An array of values of the field items, or NULL to unset the field.
    */
   public function setValue($values, $notify = TRUE) {
-    // Notify the parent of any changes to be made.
-    if ($notify && isset($this->parent)) {
-      $this->parent->onChange($this->name);
-    }
     if (!isset($values) || $values === array()) {
       $this->list = $values;
     }
@@ -72,6 +68,10 @@ public function setValue($values, $notify = TRUE) {
         }
       }
     }
+    // Notify the parent of any changes.
+    if ($notify && isset($this->parent)) {
+      $this->parent->onChange($this->name);
+    }
   }
 
   /**
@@ -153,7 +153,7 @@ public function offsetSet($offset, $value) {
     }
     if (is_numeric($offset)) {
       // Support setting values via typed data objects.
-      if ($value instanceof TypedDataInterface) {
+      if ($value instanceof PrimitiveInterface) {
         $value = $value->getValue();
       }
       $this->offsetGet($offset)->setValue($value);
diff --git a/core/lib/Drupal/Core/TypedData/ListInterface.php b/core/lib/Drupal/Core/TypedData/ListInterface.php
index 2711cd4..451e1af 100644
--- a/core/lib/Drupal/Core/TypedData/ListInterface.php
+++ b/core/lib/Drupal/Core/TypedData/ListInterface.php
@@ -41,7 +41,7 @@ public function getItemDefinition();
   /**
    * React to changes to a child item.
    *
-   * Note that this is invoked before any changes are applied.
+   * Note that this is invoked after any changes have been applied.
    *
    * @param $delta
    *   The delta of the item which is changed.
diff --git a/core/lib/Drupal/Core/TypedData/Plugin/DataType/Any.php b/core/lib/Drupal/Core/TypedData/Plugin/DataType/Any.php
index 9236b22..1061ffe 100644
--- a/core/lib/Drupal/Core/TypedData/Plugin/DataType/Any.php
+++ b/core/lib/Drupal/Core/TypedData/Plugin/DataType/Any.php
@@ -31,4 +31,22 @@ class Any extends TypedData {
    * @var mixed
    */
   protected $value;
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getValue() {
+    return $this->value;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setValue($value, $notify = TRUE) {
+    $this->value = $value;
+    // Notify the parent of any changes.
+    if ($notify && isset($this->parent)) {
+      $this->parent->onChange($this->name);
+    }
+  }
 }
diff --git a/core/lib/Drupal/Core/TypedData/Plugin/DataType/Binary.php b/core/lib/Drupal/Core/TypedData/Plugin/DataType/Binary.php
index 908f040..16ac5d6 100644
--- a/core/lib/Drupal/Core/TypedData/Plugin/DataType/Binary.php
+++ b/core/lib/Drupal/Core/TypedData/Plugin/DataType/Binary.php
@@ -59,10 +59,6 @@ public function getValue() {
    * Supports a PHP file resource or a (absolute) stream resource URI as value.
    */
   public function setValue($value, $notify = TRUE) {
-    // Notify the parent of any changes to be made.
-    if ($notify && isset($this->parent)) {
-      $this->parent->onChange($this->name);
-    }
     if (!isset($value)) {
       $this->handle = NULL;
       $this->uri = NULL;
@@ -76,6 +72,10 @@ public function setValue($value, $notify = TRUE) {
     else {
       $this->handle = $value;
     }
+    // Notify the parent of any changes.
+    if ($notify && isset($this->parent)) {
+      $this->parent->onChange($this->name);
+    }
   }
 
   /**
diff --git a/core/lib/Drupal/Core/TypedData/Plugin/DataType/DateTimeIso8601.php b/core/lib/Drupal/Core/TypedData/Plugin/DataType/DateTimeIso8601.php
index 59bbe8a..906b4eb 100644
--- a/core/lib/Drupal/Core/TypedData/Plugin/DataType/DateTimeIso8601.php
+++ b/core/lib/Drupal/Core/TypedData/Plugin/DataType/DateTimeIso8601.php
@@ -36,8 +36,12 @@ public function getDateTime() {
   /**
    * {@inheritdoc}
    */
-  public function setDateTime(DrupalDateTime $dateTime) {
+  public function setDateTime(DrupalDateTime $dateTime, $notify = TRUE) {
     $this->value = $dateTime->format('c');
+    // Notify the parent of any changes.
+    if ($notify && isset($this->parent)) {
+      $this->parent->onChange($this->name);
+    }
   }
 }
 
diff --git a/core/lib/Drupal/Core/TypedData/Plugin/DataType/DurationIso8601.php b/core/lib/Drupal/Core/TypedData/Plugin/DataType/DurationIso8601.php
index d83261f..9e67026 100644
--- a/core/lib/Drupal/Core/TypedData/Plugin/DataType/DurationIso8601.php
+++ b/core/lib/Drupal/Core/TypedData/Plugin/DataType/DurationIso8601.php
@@ -37,10 +37,14 @@ public function getDuration() {
   /**
    * {@inheritdoc}
    */
-  public function setDuration(\DateInterval $duration) {
+  public function setDuration(\DateInterval $duration, $notify = TRUE) {
     // Generate an ISO 8601 formatted string as supported by
     // DateInterval::__construct() and setValue().
     $this->value = $duration->format('%rP%yY%mM%dDT%hH%mM%sS');
+    // Notify the parent of any changes.
+    if ($notify && isset($this->parent)) {
+      $this->parent->onChange($this->name);
+    }
   }
 
 }
diff --git a/core/lib/Drupal/Core/TypedData/Plugin/DataType/Language.php b/core/lib/Drupal/Core/TypedData/Plugin/DataType/Language.php
index fdb7e59..87d0bdf 100644
--- a/core/lib/Drupal/Core/TypedData/Plugin/DataType/Language.php
+++ b/core/lib/Drupal/Core/TypedData/Plugin/DataType/Language.php
@@ -11,6 +11,7 @@
 use Drupal\Core\Annotation\Translation;
 use InvalidArgumentException;
 use Drupal\Core\Language\Language as LanguageObject;
+use Drupal\Core\TypedData\IdentifiableInterface;
 use Drupal\Core\TypedData\TypedData;
 
 /**
@@ -20,39 +21,36 @@
  * \Drupal\Core\Language\Language. For setting the value the language object or
  * the language code as string may be passed.
  *
- * Optionally, this class may be used as computed property, see the supported
- * settings below. E.g., it is used as 'language' property of language items.
- *
- * Supported settings (below the definition's 'settings' key) are:
- *  - langcode source: If used as computed property, the langcode property used
- *    to load the language object.
- *
  * @DataType(
  *   id = "language",
  *   label = @Translation("Language"),
  *   description = @Translation("A language object.")
  * )
  */
-class Language extends TypedData {
+class Language extends TypedData implements IdentifiableInterface {
 
   /**
-   * The language code of the language if no 'langcode source' is used.
+   * The id of the language.
    *
    * @var string
    */
-  protected $langcode;
+  protected $id;
+
+  /**
+   * @var \Drupal\Core\Language
+   */
+  protected $language;
 
   /**
    * Overrides TypedData::getValue().
+   *
+   * @return \Drupal\Core\Language\Language|null
    */
   public function getValue() {
-    if (!empty($this->definition['settings']['langcode source'])) {
-      $this->id = $this->parent->__get($this->definition['settings']['langcode source']);
-    }
-   if ($this->id) {
-      $language = language_load($this->id);
-      return $language ?: new LanguageObject(array('id' => $this->id));
+    if (!isset($this->language) && $this->id) {
+      $this->language = language_load($this->id);
     }
+    return $this->language;
   }
 
   /**
@@ -63,21 +61,19 @@ public function getValue() {
   public function setValue($value, $notify = TRUE) {
     // Support passing language objects.
     if (is_object($value)) {
-      $value = $value->id;
+      $this->id = $value->id;
+      $this->language = $value;
     }
     elseif (isset($value) && !is_scalar($value)) {
       throw new InvalidArgumentException('Value is no valid langcode or language object.');
     }
-    // Update the 'langcode source' property, if given.
-    if (!empty($this->definition['settings']['langcode source'])) {
-      $this->parent->__set($this->definition['settings']['langcode source'], $value, $notify);
-    }
     else {
-      // Notify the parent of any changes to be made.
-      if ($notify && isset($this->parent)) {
-        $this->parent->onChange($this->name);
-      }
       $this->id = $value;
+      $this->language = NULL;
+    }
+    // Notify the parent of any changes.
+    if ($notify && isset($this->parent)) {
+      $this->parent->onChange($this->name);
     }
   }
 
@@ -88,4 +84,17 @@ public function getString() {
     $language = $this->getValue();
     return $language ? $language->name : '';
   }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function id() {
+    if (isset($this->id)) {
+      return $this->id;
+    }
+    elseif (isset($this->language)) {
+      return $this->language->id;
+    }
+  }
+
 }
diff --git a/core/lib/Drupal/Core/TypedData/Plugin/DataType/Map.php b/core/lib/Drupal/Core/TypedData/Plugin/DataType/Map.php
index a033322..d8c5548 100644
--- a/core/lib/Drupal/Core/TypedData/Plugin/DataType/Map.php
+++ b/core/lib/Drupal/Core/TypedData/Plugin/DataType/Map.php
@@ -26,6 +26,10 @@
  *   id = "map",
  *   label = @Translation("Map")
  * )
+ *
+ * @todo Map should not implement get/setValue() to instead stick tighter to the
+ *   contract of ComplexDataInterface. Or, it should implement its own interface
+ *   where get/setValue() is defined.
  */
 class Map extends TypedData implements \IteratorAggregate, ComplexDataInterface {
 
@@ -84,10 +88,6 @@ public function setValue($values, $notify = TRUE) {
     if (isset($values) && !is_array($values)) {
       throw new \InvalidArgumentException("Invalid values given. Values must be represented as an associative array.");
     }
-    // Notify the parent of any changes to be made.
-    if ($notify && isset($this->parent)) {
-      $this->parent->onChange($this->name);
-    }
     $this->values = $values;
 
     // Update any existing property objects.
@@ -98,6 +98,10 @@ public function setValue($values, $notify = TRUE) {
       }
       $property->setValue($value, FALSE);
     }
+    // Notify the parent of any changes.
+    if ($notify && isset($this->parent)) {
+      $this->parent->onChange($this->name);
+    }
   }
 
   /**
@@ -131,16 +135,16 @@ public function get($property_name) {
    * Implements \Drupal\Core\TypedData\ComplexDataInterface::set().
    */
   public function set($property_name, $value, $notify = TRUE) {
-    // Notify the parent of any changes to be made.
-    if ($notify && isset($this->parent)) {
-      $this->parent->onChange($this->name);
-    }
     if ($this->getPropertyDefinition($property_name)) {
-      $this->get($property_name)->setValue($value);
+      $this->get($property_name)->setValue($value, $notify);
     }
     else {
       // Just set the plain value, which allows adding a new entry to the map.
       $this->values[$property_name] = $value;
+      // Directly notify ourselves.
+      if ($notify) {
+        $this->onChange($property_name, $value);
+      }
     }
   }
 
diff --git a/core/lib/Drupal/Core/TypedData/Plugin/DataType/TimeSpan.php b/core/lib/Drupal/Core/TypedData/Plugin/DataType/TimeSpan.php
index b0ec72a..c91fcd2 100644
--- a/core/lib/Drupal/Core/TypedData/Plugin/DataType/TimeSpan.php
+++ b/core/lib/Drupal/Core/TypedData/Plugin/DataType/TimeSpan.php
@@ -43,7 +43,7 @@ public function getDuration() {
   /**
    * {@inheritdoc}
    */
-  public function setDuration(\DateInterval $duration) {
+  public function setDuration(\DateInterval $duration, $notify = TRUE) {
     // Note that this applies the assumption of 12 month's a 30 days and
     // each year having 365 days. There is no accurate conversion for time spans
     // exceeding a day.
@@ -53,6 +53,11 @@ public function setDuration(\DateInterval $duration) {
       ($duration->h * 60 * 60) +
       ($duration->i * 60) +
        $duration->s;
+
+    // Notify the parent of any changes.
+    if ($notify && isset($this->parent)) {
+      $this->parent->onChange($this->name);
+    }
   }
 
 }
diff --git a/core/lib/Drupal/Core/TypedData/Plugin/DataType/Timestamp.php b/core/lib/Drupal/Core/TypedData/Plugin/DataType/Timestamp.php
index 18c99dc..c0cad02 100644
--- a/core/lib/Drupal/Core/TypedData/Plugin/DataType/Timestamp.php
+++ b/core/lib/Drupal/Core/TypedData/Plugin/DataType/Timestamp.php
@@ -41,7 +41,11 @@ public function getDateTime() {
   /**
    * {@inheritdoc}
    */
-  public function setDateTime(DrupalDateTime $dateTime) {
+  public function setDateTime(DrupalDateTime $dateTime, $notify = TRUE) {
     $this->value = $dateTime->getTimestamp();
+    // Notify the parent of any changes.
+    if ($notify && isset($this->parent)) {
+      $this->parent->onChange($this->name);
+    }
   }
 }
diff --git a/core/lib/Drupal/Core/TypedData/PrimitiveBase.php b/core/lib/Drupal/Core/TypedData/PrimitiveBase.php
index 1ba9319..7b0201e 100644
--- a/core/lib/Drupal/Core/TypedData/PrimitiveBase.php
+++ b/core/lib/Drupal/Core/TypedData/PrimitiveBase.php
@@ -30,10 +30,17 @@ public function getValue() {
    * {@inheritdoc}
    */
   public function setValue($value, $notify = TRUE) {
-    // Notify the parent of any changes to be made.
+    $this->value = $value;
+    // Notify the parent of any changes.
     if ($notify && isset($this->parent)) {
       $this->parent->onChange($this->name);
     }
-    $this->value = $value;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getString() {
+    return (string) $this->getValue();
   }
 }
diff --git a/core/lib/Drupal/Core/TypedData/PrimitiveInterface.php b/core/lib/Drupal/Core/TypedData/PrimitiveInterface.php
index b2293e2..35f16bd 100644
--- a/core/lib/Drupal/Core/TypedData/PrimitiveInterface.php
+++ b/core/lib/Drupal/Core/TypedData/PrimitiveInterface.php
@@ -10,7 +10,7 @@
 /**
  * Interface for primitive data.
  */
-interface PrimitiveInterface {
+interface PrimitiveInterface extends StringableInterface {
 
   /**
    * Gets the primitive data value.
diff --git a/core/lib/Drupal/Core/TypedData/StringableInterface.php b/core/lib/Drupal/Core/TypedData/StringableInterface.php
new file mode 100644
index 0000000..06b9064
--- /dev/null
+++ b/core/lib/Drupal/Core/TypedData/StringableInterface.php
@@ -0,0 +1,22 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\TypedData\StringableInterface.
+ */
+
+namespace Drupal\Core\TypedData;
+
+/**
+ * Interface for casting a typed data value to a string.
+ */
+interface StringableInterface {
+
+  /**
+   * Returns a string representation of the data.
+   *
+   * @return string
+   */
+  public function getString();
+
+}
diff --git a/core/lib/Drupal/Core/TypedData/TypedData.php b/core/lib/Drupal/Core/TypedData/TypedData.php
index 8bfa215..e90d12e 100644
--- a/core/lib/Drupal/Core/TypedData/TypedData.php
+++ b/core/lib/Drupal/Core/TypedData/TypedData.php
@@ -15,7 +15,7 @@
  * Classes deriving from this base class have to declare $value
  * or override getValue() or setValue().
  */
-abstract class TypedData implements TypedDataInterface, PluginInspectionInterface {
+abstract class TypedData implements TypedDataInterface, PluginInspectionInterface, ValidatableInterface, ContextAwareInterface, DefaultableInterface {
 
   /**
    * The data definition.
@@ -34,7 +34,7 @@
   /**
    * The parent typed data object.
    *
-   * @var \Drupal\Core\TypedData\TypedDataInterface
+   * @var \Drupal\Core\TypedData\ComplexDataInterface
    */
   protected $parent;
 
@@ -46,26 +46,19 @@
    * @param string $name
    *   (optional) The name of the created property, or NULL if it is the root
    *   of a typed data tree. Defaults to NULL.
-   * @param \Drupal\Core\TypedData\TypedDataInterface $parent
+   * @param \Drupal\Core\TypedData\ComplexDataInterface $parent
    *   (optional) The parent object of the data property, or NULL if it is the
    *   root of a typed data tree. Defaults to NULL.
    *
    * @see Drupal\Core\TypedData\TypedDataManager::create()
    */
-  public function __construct(array $definition, $name = NULL, TypedDataInterface $parent = NULL) {
+  public function __construct(array $definition, $name = NULL, $parent = NULL) {
     $this->definition = $definition;
     $this->parent = $parent;
     $this->name = $name;
   }
 
   /**
-   * Implements \Drupal\Core\TypedData\TypedDataInterface::getType().
-   */
-  public function getType() {
-    return $this->definition['type'];
-  }
-
-  /**
    * {@inheritdoc}
    */
   public function getPluginId() {
@@ -87,32 +80,7 @@ public function getDefinition() {
   }
 
   /**
-   * Implements \Drupal\Core\TypedData\TypedDataInterface::getValue().
-   */
-  public function getValue() {
-    return $this->value;
-  }
-
-  /**
-   * Implements \Drupal\Core\TypedData\TypedDataInterface::setValue().
-   */
-  public function setValue($value, $notify = TRUE) {
-    // Notify the parent of any changes to be made.
-    if ($notify && isset($this->parent)) {
-      $this->parent->onChange($this->name);
-    }
-    $this->value = $value;
-  }
-
-  /**
-   * Implements \Drupal\Core\TypedData\TypedDataInterface::getString().
-   */
-  public function getString() {
-    return (string) $this->getValue();
-  }
-
-  /**
-   * Implements \Drupal\Core\TypedData\TypedDataInterface::getConstraints().
+   * {@inheritdoc}
    */
   public function getConstraints() {
     // @todo: Add the typed data manager as proper dependency.
@@ -120,7 +88,7 @@ public function getConstraints() {
   }
 
   /**
-   * Implements \Drupal\Core\TypedData\TypedDataInterface::validate().
+   * {@inheritdoc}
    */
   public function validate() {
     // @todo: Add the typed data manager as proper dependency.
@@ -137,22 +105,22 @@ public function applyDefaultValue($notify = TRUE) {
   }
 
   /**
-   * Implements \Drupal\Core\TypedData\TypedDataInterface::setContext().
+   * {@inheritdoc}
    */
-  public function setContext($name = NULL, TypedDataInterface $parent = NULL) {
+  public function setContext($name = NULL, $parent = NULL) {
     $this->parent = $parent;
     $this->name = $name;
   }
 
   /**
-   * Implements \Drupal\Core\TypedData\TypedDataInterface::getName().
+   * {@inheritdoc}
    */
   public function getName() {
     return $this->name;
   }
 
   /**
-   * Implements \Drupal\Core\TypedData\TypedDataInterface::getRoot().
+   * {@inheritdoc}
    */
   public function getRoot() {
     if (isset($this->parent)) {
@@ -163,7 +131,7 @@ public function getRoot() {
   }
 
   /**
-   * Implements \Drupal\Core\TypedData\TypedDataInterface::getPropertyPath().
+   * {@inheritdoc}
    */
   public function getPropertyPath() {
     if (isset($this->parent)) {
@@ -181,9 +149,7 @@ public function getPropertyPath() {
   }
 
   /**
-   * Implements \Drupal\Core\TypedData\TypedDataInterface::getParent().
-   *
-   * @return \Drupal\Core\Entity\Field\FieldInterface
+   * {@inheritdoc}
    */
   public function getParent() {
     return $this->parent;
diff --git a/core/lib/Drupal/Core/TypedData/TypedDataInterface.php b/core/lib/Drupal/Core/TypedData/TypedDataInterface.php
index 96229b6..66ac1a5 100644
--- a/core/lib/Drupal/Core/TypedData/TypedDataInterface.php
+++ b/core/lib/Drupal/Core/TypedData/TypedDataInterface.php
@@ -7,143 +7,16 @@
 
 namespace Drupal\Core\TypedData;
 
-use Drupal\user;
-
 /**
  * Interface for typed data objects.
  */
 interface TypedDataInterface {
 
   /**
-   * Gets the data type.
-   *
-   * @return string
-   *   The data type of the wrapped data.
-   */
-  public function getType();
-
-  /**
    * Gets the data definition.
    *
    * @return array
    *   The data definition array.
    */
   public function getDefinition();
-
-  /**
-   * Gets the data value.
-   *
-   * @return mixed
-   */
-  public function getValue();
-
-  /**
-   * Sets the data value.
-   *
-   * @param mixed|null $value
-   *   The value to set in the format as documented for the data type or NULL to
-   *   unset the data value.
-   * @param bool $notify
-   *   (optional) Whether to notify the parent object of the change. Defaults to
-   *   TRUE. If a property is updated from a parent object, set it to FALSE to
-   *   avoid being notified again.
-   *
-   * @throws \Drupal\Core\TypedData\ReadOnlyException
-   *   If the data is read-only.
-   */
-  public function setValue($value, $notify = TRUE);
-
-  /**
-   * Returns a string representation of the data.
-   *
-   * @return string
-   */
-  public function getString();
-
-  /**
-   * Gets a list of validation constraints.
-   *
-   * @return array
-   *   Array of constraints, each being an instance of
-   *   \Symfony\Component\Validator\Constraint.
-   */
-  public function getConstraints();
-
-  /**
-   * Validates the currently set data value.
-   *
-   * @return \Symfony\Component\Validator\ConstraintViolationListInterface
-   *   A list of constraint violations. If the list is empty, validation
-   *   succeeded.
-   */
-  public function validate();
-
-  /**
-   * Applies the default value.
-   *
-   * @param bool $notify
-   *   (optional) Whether to notify the parent object of the change. Defaults to
-   *   TRUE. If a property is updated from a parent object, set it to FALSE to
-   *   avoid being notified again.
-   *
-   * @return \Drupal\Core\TypedData\TypedDataInterface
-   *   Returns itself to allow for chaining.
-   */
-  public function applyDefaultValue($notify = TRUE);
-
-  /**
-   * Returns the name of a property or item.
-   *
-   * @return string
-   *   If the data is a property of some complex data, the name of the property.
-   *   If the data is an item of a list, the name is the numeric position of the
-   *   item in the list, starting with 0. Otherwise, NULL is returned.
-   */
-  public function getName();
-
-  /**
-   * Returns the parent data structure; i.e. either complex data or a list.
-   *
-   * @return \Drupal\Core\TypedData\ComplexDataInterface|\Drupal\Core\TypedData\ListInterface
-   *   The parent data structure, either complex data or a list; or NULL if this
-   *   is the root of the typed data tree.
-   */
-  public function getParent();
-
-  /**
-   * Returns the root of the typed data tree.
-   *
-   * Returns the root data for a tree of typed data objects; e.g. for an entity
-   * field item the root of the tree is its parent entity object.
-   *
-   * @return \Drupal\Core\TypedData\ComplexDataInterface|\Drupal\Core\TypedData\ListInterface
-   *   The root data structure, either complex data or a list.
-   */
-  public function getRoot();
-
-  /**
-   * Returns the property path of the data.
-   *
-   * The trail of property names relative to the root of the typed data tree,
-   * separated by dots; e.g. 'field_text.0.format'.
-   *
-   * @return string
-   *   The property path relative to the root of the typed tree, or an empty
-   *   string if this is the root.
-   */
-  public function getPropertyPath();
-
-  /**
-   * Sets the context of a property or item via a context aware parent.
-   *
-   * This method is supposed to be called by the factory only.
-   *
-   * @param string $name
-   *   (optional) The name of the property or the delta of the list item,
-   *   or NULL if it is the root of a typed data tree. Defaults to NULL.
-   * @param \Drupal\Core\TypedData\TypedDataInterface $parent
-   *   (optional) The parent object of the data property, or NULL if it is the
-   *   root of a typed data tree. Defaults to NULL.
-   */
-  public function setContext($name = NULL, TypedDataInterface $parent = NULL);
 }
diff --git a/core/lib/Drupal/Core/TypedData/TypedDataManager.php b/core/lib/Drupal/Core/TypedData/TypedDataManager.php
index f0e8034..c8c1f98 100644
--- a/core/lib/Drupal/Core/TypedData/TypedDataManager.php
+++ b/core/lib/Drupal/Core/TypedData/TypedDataManager.php
@@ -14,6 +14,7 @@
 use Drupal\Core\Plugin\DefaultPluginManager;
 use InvalidArgumentException;
 use Drupal\Core\TypedData\Validation\MetadataFactory;
+use Drupal\Core\TypedData\ContextAwareInterface;
 use Drupal\Core\Validation\ConstraintManager;
 use Drupal\Core\Validation\DrupalTranslator;
 use Symfony\Component\Validator\ValidatorInterface;
@@ -198,7 +199,7 @@ public function getInstance(array $options) {
    * property path, i.e. all property instances having the same property path
    * and inheriting from the same data type are prototyped.
    *
-   * @param \Drupal\Core\TypedData\TypedDataInterface $object
+   * @param \Drupal\Core\TypedData\ContextAwareInterface $object
    *   The parent typed data object, implementing the TypedDataInterface and
    *   either the ListInterface or the ComplexDataInterface.
    * @param string $property_name
@@ -219,18 +220,16 @@ public function getInstance(array $options) {
    * @todo: Add type-hinting to $object once entities implement the
    *   TypedDataInterface.
    */
-  public function getPropertyInstance($object, $property_name, $value = NULL) {
-    if ($root = $object->getRoot()) {
-      $key = $root->getType() . ':' . $object->getPropertyPath() . '.';
-      // If we are creating list items, we always use 0 in the key as all list
-      // items look the same.
-      $key .= is_numeric($property_name) ? 0 : $property_name;
-    }
-    else {
-      // Missing context, thus we cannot determine a unique key for prototyping.
-      // Fall back to create a new prototype on each call.
-      $key = FALSE;
+  public function getPropertyInstance(ContextAwareInterface $object, $property_name, $value = NULL) {
+    $definition = $object->getRoot()->getDefinition();
+    $key = $definition['type'];
+    if (isset($definition['settings'])) {
+      $key .= ':' . implode(',', $definition['settings']);
     }
+    $key .= ':' . $object->getPropertyPath() . '.';
+    // If we are creating list items, we always use 0 in the key as all list
+    // items look the same.
+    $key .= is_numeric($property_name) ? 0 : $property_name;
 
     // Make sure we have a prototype. Then, clone the prototype and set object
     // specific values, i.e. the value and the context.
@@ -384,4 +383,26 @@ public function getConstraints($definition) {
     }
     return $constraints;
   }
+
+  /**
+   * Decided whether or not an object is typed data or not.
+   *
+   * @param mixed $object
+   *
+   * @return boolean
+   *   Returns TRUE if $object is an instance of any of the typed data
+   *   interfaces, else FALSE.
+   */
+  public function isTypedData($object) {
+    if ($object instanceof ComplexDataInterface) {
+      return TRUE;
+    }
+    elseif ($object instanceof ListInterface) {
+      return TRUE;
+    }
+    elseif ($object instanceof PrimitiveInterface) {
+      return TRUE;
+    }
+    return FALSE;
+  }
 }
diff --git a/core/lib/Drupal/Core/TypedData/ValidatableInterface.php b/core/lib/Drupal/Core/TypedData/ValidatableInterface.php
new file mode 100644
index 0000000..ac0af19
--- /dev/null
+++ b/core/lib/Drupal/Core/TypedData/ValidatableInterface.php
@@ -0,0 +1,33 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\TypedData\ValidatableInterface.
+ */
+
+namespace Drupal\Core\TypedData;
+
+/**
+ * Interface for checking access.
+ */
+interface ValidatableInterface {
+
+  /**
+   * Gets a list of validation constraints.
+   *
+   * @return array
+   *   Array of constraints, each being an instance of
+   *   \Symfony\Component\Validator\Constraint.
+   */
+  public function getConstraints();
+
+  /**
+   * Validates the currently set data value.
+   *
+   * @return \Symfony\Component\Validator\ConstraintViolationListInterface
+   *   A list of constraint violations. If the list is empty, validation
+   *   succeeded.
+   */
+  public function validate();
+
+}
diff --git a/core/lib/Drupal/Core/TypedData/Validation/Metadata.php b/core/lib/Drupal/Core/TypedData/Validation/Metadata.php
index 73bfc8b..0ef1b8a 100644
--- a/core/lib/Drupal/Core/TypedData/Validation/Metadata.php
+++ b/core/lib/Drupal/Core/TypedData/Validation/Metadata.php
@@ -7,12 +7,13 @@
 
 namespace Drupal\Core\TypedData\Validation;
 
-use Drupal\Core\TypedData\TypedDataInterface;
 use Symfony\Component\Validator\ValidationVisitorInterface;
 use Symfony\Component\Validator\PropertyMetadataInterface;
 
 /**
  * Typed data implementation of the validator MetadataInterface.
+ *
+ * @todo We need logic depending on each type of data.
  */
 class Metadata implements PropertyMetadataInterface {
 
@@ -48,7 +49,7 @@ class Metadata implements PropertyMetadataInterface {
    * @param \Drupal\Core\TypedData\Validation\MetadataFactory $factory
    *   The factory to use for instantiating property metadata.
    */
-  public function __construct(TypedDataInterface $typed_data, $name = '', MetadataFactory $factory) {
+  public function __construct($typed_data, $name = '', MetadataFactory $factory) {
     $this->typedData = $typed_data;
     $this->name = $name;
     $this->factory = $factory;
diff --git a/core/lib/Drupal/Core/TypedData/Validation/MetadataFactory.php b/core/lib/Drupal/Core/TypedData/Validation/MetadataFactory.php
index 2858daf..44af36f 100644
--- a/core/lib/Drupal/Core/TypedData/Validation/MetadataFactory.php
+++ b/core/lib/Drupal/Core/TypedData/Validation/MetadataFactory.php
@@ -9,7 +9,6 @@
 
 use Drupal\Core\TypedData\ComplexDataInterface;
 use Drupal\Core\TypedData\ListInterface;
-use Drupal\Core\TypedData\TypedDataInterface;
 use Symfony\Component\Validator\MetadataFactoryInterface;
 
 /**
@@ -27,7 +26,7 @@ class MetadataFactory implements MetadataFactoryInterface {
    *   the data is the root of the typed data tree.
    */
   public function getMetadataFor($typed_data, $name = '') {
-    if (!$typed_data instanceof TypedDataInterface) {
+    if (!\Drupal::typedData()->isTypedData($typed_data)) {
       throw new \InvalidArgumentException('The passed value must be a typed data object.');
     }
     $is_container = $typed_data instanceof ComplexDataInterface || $typed_data instanceof ListInterface;
@@ -39,6 +38,6 @@ public function getMetadataFor($typed_data, $name = '') {
    * Implements MetadataFactoryInterface::hasMetadataFor().
    */
   public function hasMetadataFor($value) {
-    return $value instanceof TypedDataInterface;
+    return \Drupal::typedData()->isTypedData($value);
   }
 }
diff --git a/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/BundleConstraint.php b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/BundleConstraint.php
index f6ea289..ebd844b 100644
--- a/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/BundleConstraint.php
+++ b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/BundleConstraint.php
@@ -20,7 +20,7 @@
  * @Plugin(
  *   id = "Bundle",
  *   label = @Translation("Bundle", context = "Validation"),
- *   type = "entity"
+ *   type = { "entity", "entity_reference" }
  * )
  */
 class BundleConstraint extends Constraint {
diff --git a/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/BundleConstraintValidator.php b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/BundleConstraintValidator.php
index a84251e..42f09ca 100644
--- a/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/BundleConstraintValidator.php
+++ b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/BundleConstraintValidator.php
@@ -18,10 +18,7 @@ class BundleConstraintValidator extends ConstraintValidator {
   /**
    * Implements \Symfony\Component\Validator\ConstraintValidatorInterface::validate().
    */
-  public function validate($typed_data, Constraint $constraint) {
-    // If the entity is contained in a reference, unwrap it first.
-    $entity = isset($typed_data) && !($typed_data instanceof EntityInterface) ? $typed_data->getValue() : FALSE;
-
+  public function validate($entity, Constraint $constraint) {
     if (!empty($entity) && !in_array($entity->bundle(), $constraint->getBundleOption())) {
       $this->context->addViolation($constraint->message, array('%bundle', implode(', ', $constraint->getBundleOption())));
     }
diff --git a/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/EntityTypeConstraint.php b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/EntityTypeConstraint.php
index 1d38ae5..d480fa1 100644
--- a/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/EntityTypeConstraint.php
+++ b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/EntityTypeConstraint.php
@@ -20,7 +20,7 @@
  * @Plugin(
  *   id = "EntityType",
  *   label = @Translation("Entity type", context = "Validation"),
- *   type = "entity"
+ *   type = { "entity", "entity_reference" }
  * )
  */
 class EntityTypeConstraint extends Constraint {
diff --git a/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/EntityTypeConstraintValidator.php b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/EntityTypeConstraintValidator.php
index 31c7cb2..304a85c 100644
--- a/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/EntityTypeConstraintValidator.php
+++ b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/EntityTypeConstraintValidator.php
@@ -19,9 +19,7 @@ class EntityTypeConstraintValidator extends ConstraintValidator {
   /**
    * Implements \Symfony\Component\Validator\ConstraintValidatorInterface::validate().
    */
-  public function validate($typed_data, Constraint $constraint) {
-    // If the entity is contained in a reference, unwrap it first.
-    $entity = isset($typed_data) && !($typed_data instanceof EntityInterface) ? $typed_data->getValue() : FALSE;
+  public function validate($entity, Constraint $constraint) {
 
     if (!empty($entity) && $entity->entityType() != $constraint->type) {
       $this->context->addViolation($constraint->message, array('%type' => $constraint->type));
diff --git a/core/modules/comment/comment.module b/core/modules/comment/comment.module
index 604cb93..8ba44d1 100644
--- a/core/modules/comment/comment.module
+++ b/core/modules/comment/comment.module
@@ -1482,7 +1482,7 @@ function comment_preprocess_block(&$variables) {
 function comment_prepare_author(Comment $comment) {
   // The account has been pre-loaded by CommentRenderController::buildContent().
   $account = $comment->uid->entity;
-  if (!$account) {
+  if (empty($account->uid->value)) {
     $account = entity_create('user', array('uid' => 0, 'name' => $comment->name->value, 'homepage' => $comment->homepage->value));
   }
   return $account->getBCEntity();
diff --git a/core/modules/comment/lib/Drupal/comment/FieldNewValue.php b/core/modules/comment/lib/Drupal/comment/FieldNewValue.php
index 8f9c392..bd2fd9d 100644
--- a/core/modules/comment/lib/Drupal/comment/FieldNewValue.php
+++ b/core/modules/comment/lib/Drupal/comment/FieldNewValue.php
@@ -15,6 +15,7 @@
  * A computed property for the integer value of the 'new' field.
  *
  * @todo: Declare the list of allowed values once supported.
+ * @todo Need to implement a proper interface.
  */
 class FieldNewValue extends TypedData {
 
diff --git a/core/modules/config/lib/Drupal/config/Tests/ConfigSchemaTest.php b/core/modules/config/lib/Drupal/config/Tests/ConfigSchemaTest.php
index d3bceb8..4616efe 100644
--- a/core/modules/config/lib/Drupal/config/Tests/ConfigSchemaTest.php
+++ b/core/modules/config/lib/Drupal/config/Tests/ConfigSchemaTest.php
@@ -162,13 +162,11 @@ function testSchemaData() {
     // Try some simple properties.
     $meta = config_typed()->get('system.site');
     $property = $meta->get('name');
-    $this->assertTrue(is_a($property, 'Drupal\Core\TypedData\Plugin\DataType\String'), 'Got the right wrapper fo the site name property.');
-    $this->assertEqual($property->getType(), 'label', 'Got the right string type for site name data.');
+    $this->assertTrue($property instanceof \Drupal\Core\TypedData\Plugin\DataType\String, 'Got the right wrapper fo the site name property.');
     $this->assertEqual($property->getValue(), 'Drupal', 'Got the right string value for site name data.');
 
     $property = $meta->get('page')->get('front');
-    $this->assertTrue(is_a($property, 'Drupal\Core\TypedData\Plugin\DataType\String'), 'Got the right wrapper fo the page.front property.');
-    $this->assertEqual($property->getType(), 'path', 'Got the right type for page.front data (undefined).');
+    $this->assertTrue($property instanceof \Drupal\Core\TypedData\Plugin\DataType\String, 'Got the right wrapper fo the page.front property.');
     $this->assertEqual($property->getValue(), 'user', 'Got the right value for page.front data.');
 
     // Check nested array of properties.
@@ -192,7 +190,7 @@ function testSchemaData() {
     $ieid = key($effects->getValue());
     $effect = $effects[$ieid];
     $this->assertTrue(count($effect['data']) && $effect['name']->getValue() == 'image_scale', 'Got data for the image scale effect from metadata.');
-    $this->assertEqual($effect['data']['width']->getType(), 'integer', 'Got the right type for the scale effect width.');
+    $this->assertTrue($effect['data']['width'] instanceof \Drupal\Core\TypedData\Plugin\DataType\Integer, 'Got the right type for the scale effect width.');
     $this->assertEqual($effect['data']['width']->getValue(), 480, 'Got the right value for the scale effect width.' );
 
     // Finally update some object using a configuration wrapper.
diff --git a/core/modules/content_translation/lib/Drupal/content_translation/Tests/Views/TranslationLinkTest.php b/core/modules/content_translation/lib/Drupal/content_translation/Tests/Views/TranslationLinkTest.php
index 1f5e457..b26b0a5 100644
--- a/core/modules/content_translation/lib/Drupal/content_translation/Tests/Views/TranslationLinkTest.php
+++ b/core/modules/content_translation/lib/Drupal/content_translation/Tests/Views/TranslationLinkTest.php
@@ -46,6 +46,11 @@ function setUp() {
 
     parent::setUp();
 
+    // Assign user 1  a language code so that the entity can be translated.
+    $user = user_load(1);
+    $user->langcode = 'en';
+    $user->save();
+
     ViewTestData::importTestViews(get_class($this), array('content_translation_test_views'));
   }
 
diff --git a/core/modules/field/lib/Drupal/field/Plugin/Type/FieldType/ConfigEntityReferenceItemBase.php b/core/modules/field/lib/Drupal/field/Plugin/Type/FieldType/ConfigEntityReferenceItemBase.php
index 7229a9a..ff4472f 100644
--- a/core/modules/field/lib/Drupal/field/Plugin/Type/FieldType/ConfigEntityReferenceItemBase.php
+++ b/core/modules/field/lib/Drupal/field/Plugin/Type/FieldType/ConfigEntityReferenceItemBase.php
@@ -57,14 +57,15 @@ public function getInstance() {
    * {@inheritdoc}
    */
   public function getPropertyDefinitions() {
-    // Definitions vary by entity type, so key them by entity type.
-    $target_type = $this->definition['settings']['target_type'];
+    // Definitions vary by entity type and bundle, so key them accordingly.
+    $key = $this->definition['settings']['target_type'] . ':';
+    $key .= isset($this->definition['settings']['target_bundle']) ? $this->definition['settings']['target_bundle'] : '';
 
-    if (!isset(self::$propertyDefinitions[$target_type])) {
+    if (!isset(static::$propertyDefinitions[$key])) {
       // Call the parent to define the target_id and entity properties.
       parent::getPropertyDefinitions();
 
-      static::$propertyDefinitions[$target_type]['revision_id'] = array(
+      static::$propertyDefinitions[$key]['revision_id'] = array(
         // @todo: Lookup the entity type's ID data type and use it here.
         'type' => 'integer',
         'label' => t('Revision ID'),
@@ -72,18 +73,18 @@ public function getPropertyDefinitions() {
           'Range' => array('min' => 0),
         ),
       );
-      static::$propertyDefinitions[$target_type]['label'] = array(
+      static::$propertyDefinitions[$key]['label'] = array(
         'type' => 'string',
         'label' => t('Label (auto-create)'),
         'computed' => TRUE,
       );
-      static::$propertyDefinitions[$target_type]['access'] = array(
+      static::$propertyDefinitions[$key]['access'] = array(
         'type' => 'boolean',
         'label' => t('Access'),
         'computed' => TRUE,
       );
     }
-    return static::$propertyDefinitions[$target_type];
+    return static::$propertyDefinitions[$key];
   }
 
   /**
diff --git a/core/modules/field/lib/Drupal/field/Plugin/Type/FieldType/ConfigField.php b/core/modules/field/lib/Drupal/field/Plugin/Type/FieldType/ConfigField.php
index dfc4fba..202071c 100644
--- a/core/modules/field/lib/Drupal/field/Plugin/Type/FieldType/ConfigField.php
+++ b/core/modules/field/lib/Drupal/field/Plugin/Type/FieldType/ConfigField.php
@@ -7,7 +7,6 @@
 
 namespace Drupal\field\Plugin\Type\FieldType;
 
-use Drupal\Core\TypedData\TypedDataInterface;
 use Drupal\Core\Entity\Field\Field;
 use Drupal\field\Field as FieldAPI;
 
@@ -26,7 +25,7 @@ class ConfigField extends Field implements ConfigFieldInterface {
   /**
    * {@inheritdoc}
    */
-  public function __construct(array $definition, $name = NULL, TypedDataInterface $parent = NULL) {
+  public function __construct(array $definition, $name = NULL, $parent = NULL) {
     parent::__construct($definition, $name, $parent);
     if (isset($definition['instance'])) {
       $this->instance = $definition['instance'];
diff --git a/core/modules/file/lib/Drupal/file/Type/FileItem.php b/core/modules/file/lib/Drupal/file/Type/FileItem.php
index 9b2cc4c..c8f1a9c 100644
--- a/core/modules/file/lib/Drupal/file/Type/FileItem.php
+++ b/core/modules/file/lib/Drupal/file/Type/FileItem.php
@@ -28,20 +28,23 @@ class FileItem extends ConfigEntityReferenceItemBase {
    */
   public function getPropertyDefinitions() {
     $this->definition['settings']['target_type'] = 'file';
+    // Definitions vary by entity type and bundle, so key them accordingly.
+    $key = $this->definition['settings']['target_type'] . ':';
+    $key .= isset($this->definition['settings']['target_bundle']) ? $this->definition['settings']['target_bundle'] : '';
 
-    if (!isset(static::$propertyDefinitions)) {
-      static::$propertyDefinitions = parent::getPropertyDefinitions();
+    if (!isset(static::$propertyDefinitions[$key])) {
+      static::$propertyDefinitions[$key] = parent::getPropertyDefinitions();
 
-      static::$propertyDefinitions['display'] = array(
+      static::$propertyDefinitions[$key]['display'] = array(
         'type' => 'boolean',
         'label' => t('Flag to control whether this file should be displayed when viewing content.'),
       );
-      static::$propertyDefinitions['description'] = array(
+      static::$propertyDefinitions[$key]['description'] = array(
         'type' => 'string',
         'label' => t('A description of the file.'),
       );
     }
-    return static::$propertyDefinitions;
+    return static::$propertyDefinitions[$key];
   }
 
 }
diff --git a/core/modules/image/lib/Drupal/image/Type/ImageItem.php b/core/modules/image/lib/Drupal/image/Type/ImageItem.php
index 7d441fd..3b86fe4 100644
--- a/core/modules/image/lib/Drupal/image/Type/ImageItem.php
+++ b/core/modules/image/lib/Drupal/image/Type/ImageItem.php
@@ -28,28 +28,31 @@ class ImageItem extends ConfigEntityReferenceItemBase {
    */
   public function getPropertyDefinitions() {
     $this->definition['settings']['target_type'] = 'file';
+    // Definitions vary by entity type and bundle, so key them accordingly.
+    $key = $this->definition['settings']['target_type'] . ':';
+    $key .= isset($this->definition['settings']['target_bundle']) ? $this->definition['settings']['target_bundle'] : '';
 
-    if (!isset(static::$propertyDefinitions)) {
-      static::$propertyDefinitions = parent::getPropertyDefinitions();
+    if (!isset(static::$propertyDefinitions[$key])) {
+      static::$propertyDefinitions[$key] = parent::getPropertyDefinitions();
 
-      static::$propertyDefinitions['alt'] = array(
+      static::$propertyDefinitions[$key]['alt'] = array(
         'type' => 'string',
         'label' => t("Alternative image text, for the image's 'alt' attribute."),
       );
-      static::$propertyDefinitions['title'] = array(
+      static::$propertyDefinitions[$key]['title'] = array(
         'type' => 'string',
         'label' => t("Image title text, for the image's 'title' attribute."),
       );
-      static::$propertyDefinitions['width'] = array(
+      static::$propertyDefinitions[$key]['width'] = array(
         'type' => 'integer',
         'label' => t('The width of the image in pixels.'),
       );
-      static::$propertyDefinitions['height'] = array(
+      static::$propertyDefinitions[$key]['height'] = array(
         'type' => 'integer',
         'label' => t('The height of the image in pixels.'),
       );
     }
-    return static::$propertyDefinitions;
+    return static::$propertyDefinitions[$key];
   }
 
 }
diff --git a/core/modules/locale/lib/Drupal/locale/LocaleTypedConfig.php b/core/modules/locale/lib/Drupal/locale/LocaleTypedConfig.php
index 5d6b200..9dca634 100644
--- a/core/modules/locale/lib/Drupal/locale/LocaleTypedConfig.php
+++ b/core/modules/locale/lib/Drupal/locale/LocaleTypedConfig.php
@@ -8,7 +8,6 @@
 namespace Drupal\locale;
 
 use Drupal\Core\Language\Language;
-use Drupal\Core\TypedData\ContextAwareInterface;
 use Drupal\Core\Config\Schema\Element;
 use Drupal\Core\Config\Schema\ArrayElement;
 
@@ -168,7 +167,7 @@ protected function getArrayTranslation(ArrayElement $element, array $options) {
    * @return bool
    *   Whether the element fits the translation criteria.
    */
-  protected function translateElement(\Drupal\Core\TypedData\TypedDataInterface $element, array $options) {
+  protected function translateElement($element, array $options) {
     if ($this->canTranslate($options['source'], $options['target'])) {
       $definition = $element->getDefinition();
       $value = $element->getValue();
diff --git a/core/modules/locale/lib/Drupal/locale/Tests/LocaleContentTest.php b/core/modules/locale/lib/Drupal/locale/Tests/LocaleContentTest.php
index c55927f..b53ba51 100644
--- a/core/modules/locale/lib/Drupal/locale/Tests/LocaleContentTest.php
+++ b/core/modules/locale/lib/Drupal/locale/Tests/LocaleContentTest.php
@@ -97,6 +97,7 @@ function testContentTypeLanguageConfiguration() {
     $this->drupalPost("admin/structure/types/manage/{$type2->type}", $edit, t('Save content type'));
     $this->assertRaw(t('The content type %type has been updated.', array('%type' => $type2->name)));
     $this->drupalLogout();
+    drupal_static_reset('language_list');
 
     // Verify language selection is not present on the node add form.
     $this->drupalLogin($web_user);
@@ -153,6 +154,7 @@ function testContentTypeDirLang() {
     $edit = array();
     $edit['predefined_langcode'] = 'ar';
     $this->drupalPost('admin/config/regional/language/add', $edit, t('Add language'));
+    drupal_static_reset('language_list');
 
     // Install Spanish language.
     $edit = array();
diff --git a/core/modules/menu/lib/Drupal/menu/Tests/MenuTest.php b/core/modules/menu/lib/Drupal/menu/Tests/MenuTest.php
index b914837..d0fbb8c 100644
--- a/core/modules/menu/lib/Drupal/menu/Tests/MenuTest.php
+++ b/core/modules/menu/lib/Drupal/menu/Tests/MenuTest.php
@@ -419,8 +419,10 @@ public function testBlockContextualLinks() {
   public function testMenuBundles() {
     $this->drupalLogin($this->big_user);
     $menu = $this->addCustomMenu();
+    // Clear the entity info cache to ensure the static caches are rebuilt.
+    entity_info_cache_clear();
     $bundles = entity_get_bundles('menu_link');
-    $this->assertTrue($bundles[$menu->id()]);
+    $this->assertTrue(isset($bundles[$menu->id()]));
     $menus = menu_list_system_menus();
     $menus[$menu->id()] = $menu->label();
     ksort($menus);
diff --git a/core/modules/node/node.module b/core/modules/node/node.module
index b9c5bd3..447d830 100644
--- a/core/modules/node/node.module
+++ b/core/modules/node/node.module
@@ -2164,7 +2164,7 @@ function node_access($op, $node, $account = NULL, $langcode = NULL) {
 
   // If no language code was provided, default to the node's langcode.
   if (empty($langcode)) {
-    $langcode = $node->langcode;
+    $langcode = $node->language()->id;
     // If the Language module is enabled, try to use the language from content
     // negotiation.
     if (module_exists('language')) {
diff --git a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityFieldTest.php b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityFieldTest.php
index e8878be..1d69638 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityFieldTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityFieldTest.php
@@ -11,7 +11,7 @@
 use Drupal\Core\Entity\Field\FieldInterface;
 use Drupal\Core\Entity\Field\FieldItemInterface;
 use Drupal\Core\Language\Language;
-use Drupal\Core\TypedData\TypedDataInterface;
+use Drupal\Core\TypedData\PrimitiveInterface;
 
 /**
  * Tests Entity API base functionality.
@@ -339,7 +339,7 @@ protected function assertSave($entity_type) {
   public function testIntrospection() {
     // All entity variations have to have the same results.
     foreach (entity_test_entity_types() as $entity_type) {
-      $this->assertIntrospection($entity_type);
+      $this->checkIntrospection($entity_type);
     }
   }
 
@@ -349,17 +349,11 @@ public function testIntrospection() {
    * @param string $entity_type
    *   The entity type to run the tests with.
    */
-  protected function assertIntrospection($entity_type) {
-    // Test getting metadata upfront, i.e. without having an entity object.
-    $definition = array(
-      'type' => 'entity',
-      'constraints' => array(
-        'EntityType' => $entity_type,
-      ),
-      'label' => 'Test entity',
-    );
-    $wrapped_entity = $this->container->get('typed_data')->create($definition);
-    $definitions = $wrapped_entity->getPropertyDefinitions($definition);
+  protected function checkIntrospection($entity_type) {
+    // Test getting metadata upfront.
+    // @todo: Make this work without having to create entity objects.
+    $entity = entity_create($entity_type, array());
+    $definitions = $entity->getPropertyDefinitions();
     $this->assertEqual($definitions['name']['type'], 'string_field', $entity_type .': Name field found.');
     $this->assertEqual($definitions['user_id']['type'], 'entity_reference_field', $entity_type .': User field found.');
     $this->assertEqual($definitions['field_test_text']['type'], 'field_item:text', $entity_type .': Test-text-field field found.');
@@ -378,7 +372,7 @@ protected function assertIntrospection($entity_type) {
 
     $userref_properties = $entity->user_id->getPropertyDefinitions();
     $this->assertEqual($userref_properties['target_id']['type'], 'integer', $entity_type .': Entity id property of the user found.');
-    $this->assertEqual($userref_properties['entity']['type'], 'entity', $entity_type .': Entity reference property of the user found.');
+    $this->assertEqual($userref_properties['entity']['type'], 'entity_reference', $entity_type .': Entity reference property of the user found.');
 
     $textfield_properties = $entity->field_test_text->getPropertyDefinitions();
     $this->assertEqual($textfield_properties['value']['type'], 'string', $entity_type .': String value property of the test-text field found.');
@@ -439,7 +433,7 @@ protected function assertIterator($entity_type) {
         $this->assertTrue($field[0] instanceof FieldItemInterface, $entity_type . ": Item $delta of field $name implements interface.");
 
         foreach ($item as $value_name => $value_property) {
-          $this->assertTrue($value_property instanceof TypedDataInterface, $entity_type . ": Value $value_name of item $delta of field $name implements interface.");
+          $this->assertTrue($value_property instanceof PrimitiveInterface, $entity_type . ": Value $value_name of item $delta of field $name implements interface.");
 
           $value = $value_property->getValue();
           $this->assertTrue(!isset($value) || is_scalar($value) || $value instanceof EntityInterface, $entity_type . ": Value $value_name of item $delta of field $name is a primitive or an entity.");
@@ -470,21 +464,12 @@ public function testDataStructureInterfaces() {
    */
   protected function assertDataStructureInterfaces($entity_type) {
     $entity = $this->createTestEntity($entity_type);
-    $entity->save();
-    $entity_definition = array(
-      'type' => 'entity',
-      'constraints' => array(
-        'EntityType' => $entity_type,
-      ),
-      'label' => 'Test entity',
-    );
-    $wrapped_entity = $this->container->get('typed_data')->create($entity_definition, $entity);
 
     // Test using the whole tree of typed data by navigating through the tree of
     // contained properties and getting all contained strings, limited by a
     // certain depth.
     $strings = array();
-    $this->getContainedStrings($wrapped_entity, 0, $strings);
+    $this->getContainedStrings($entity, 0, $strings);
 
     // @todo: Once the user entity has defined properties this should contain
     // the user name and other user entity strings as well.
@@ -505,9 +490,9 @@ protected function assertDataStructureInterfaces($entity_type) {
    * Recursive helper for getting all contained strings,
    * i.e. properties of type string.
    */
-  public function getContainedStrings(TypedDataInterface $wrapper, $depth, array &$strings) {
+  public function getContainedStrings($wrapper, $depth, array &$strings) {
 
-    if ($wrapper->getType() == 'string') {
+    if ($wrapper instanceof \Drupal\Core\TypedData\Type\StringInterface) {
       $strings[] = $wrapper->getValue();
     }
 
@@ -527,22 +512,39 @@ public function getContainedStrings(TypedDataInterface $wrapper, $depth, array &
   }
 
   /**
+   * Makes sure data types are correctly derived for all entity types.
+   */
+  public function testDataTypes() {
+    $types = \Drupal::typedData()->getDefinitions();
+    foreach (entity_test_entity_types() as $entity_type) {
+      $this->assertTrue($types['entity:' . $entity_type]['class'], 'Entity data type registed.');
+    }
+    // Check bundle types are provided as well.
+    entity_test_create_bundle('bundle');
+    $types = \Drupal::typedData()->getDefinitions();
+    $this->assertTrue($types['entity:entity_test:bundle']['class'], 'Entity bundle data type registed.');
+  }
+
+  /**
    * Tests validation constraints provided by the Entity API.
    */
   public function testEntityConstraintValidation() {
     $entity = $this->createTestEntity('entity_test');
     $entity->save();
-    $entity_definition = array(
-      'type' => 'entity',
-      'constraints' => array(
-        'EntityType' => 'entity_test',
+    // Create a reference field item and let it reference the entity.
+    $definition = array(
+      'type' => 'entity_reference_field',
+      'settings' => array(
+        'target_type' => 'entity_test',
       ),
       'label' => 'Test entity',
     );
-    $wrapped_entity = $this->container->get('typed_data')->create($entity_definition, $entity);
+    $reference_field_item = \Drupal::TypedData()->create($definition);
+    $reference = $reference_field_item->get('entity');
+    $reference->setValue($entity);
 
     // Test validation the typed data object.
-    $violations = $wrapped_entity->validate();
+    $violations = $reference->validate();
     $this->assertEqual($violations->count(), 0);
 
     // Test validating an entity of the wrong type.
@@ -552,30 +554,31 @@ public function testEntityConstraintValidation() {
       'type' => 'page',
       'uid' => $user->id(),
     ));
-    // @todo: EntityWrapper can only handle entities with an id.
-    $node->save();
-    $wrapped_entity->setValue($node);
-    $violations = $wrapped_entity->validate();
+    $reference->setValue($node);
+    $violations = $reference->validate();
     $this->assertEqual($violations->count(), 1);
 
     // Test bundle validation.
-    $entity_definition = array(
-      'type' => 'entity',
-      'constraints' => array(
-        'EntityType' => 'node',
-        'Bundle' => 'article',
+    $definition = array(
+      'type' => 'entity_reference_field',
+      'settings' => array(
+        'target_type' => 'node',
+        'target_bundle' => 'article',
       ),
-      'label' => 'Test node',
     );
-    $wrapped_entity = $this->container->get('typed_data')->create($entity_definition, $node);
-
-    $violations = $wrapped_entity->validate();
+    $reference_field_item = \Drupal::TypedData()->create($definition);
+    $reference = $reference_field_item->get('entity');
+    $reference->setValue($node);
+    $violations = $reference->validate();
     $this->assertEqual($violations->count(), 1);
 
-    $node->type = 'article';
+    $node = entity_create('node', array(
+      'type' => 'article',
+      'uid' => $user->id(),
+    ));
     $node->save();
-    $wrapped_entity->setValue($node);
-    $violations = $wrapped_entity->validate();
+    $reference->setValue($node);
+    $violations = $reference->validate();
     $this->assertEqual($violations->count(), 0);
   }
 
diff --git a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityValidationTest.php b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityValidationTest.php
index f1a0fdb..69bc6fd 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityValidationTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityValidationTest.php
@@ -10,7 +10,6 @@
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Entity\Field\FieldInterface;
 use Drupal\Core\Entity\Field\FieldItemInterface;
-use Drupal\Core\TypedData\TypedDataInterface;
 
 /**
  * Tests Entity API base functionality.
diff --git a/core/modules/system/lib/Drupal/system/Tests/TypedData/TypedDataTest.php b/core/modules/system/lib/Drupal/system/Tests/TypedData/TypedDataTest.php
index 3558d20..57adf09 100644
--- a/core/modules/system/lib/Drupal/system/Tests/TypedData/TypedDataTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/TypedData/TypedDataTest.php
@@ -57,11 +57,11 @@ protected function createTypedData($definition, $value = NULL, $name = NULL) {
     // Construct the object.
     $data = $this->typedData->create($definition, $value, $name);
     // Assert the definition of the wrapper.
-    $this->assertTrue($data instanceof \Drupal\Core\TypedData\TypedDataInterface, 'Typed data object is an instance of the typed data interface.');
+    $this->assertTrue(\Drupal::typedData()->isTypedData($data), 'Typed data object is an instance of a typed data interface.');
     $definition = $data->getDefinition();
     $this->assertTrue(!empty($definition['type']), format_string('!type data definition was returned.', array('!type' => $definition['type'])));
     // Assert that the correct type was constructed.
-    $this->assertEqual($data->getType(), $type, format_string('!type object returned type.', array('!type' => $definition['type'])));
+    $this->assertEqual($data->getPluginId(), $type, format_string('!type object returned type.', array('!type' => $definition['type'])));
     return $data;
   }
 
@@ -319,7 +319,7 @@ public function testTypedDataLists() {
     // Test iterating.
     $count = 0;
     foreach ($typed_data as $item) {
-      $this->assertTrue($item instanceof \Drupal\Core\TypedData\TypedDataInterface);
+      $this->assertTrue($item instanceof \Drupal\Core\TypedData\Plugin\DataType\String);
       $count++;
     }
     $this->assertEqual($count, 3);
@@ -413,7 +413,7 @@ public function testTypedDataMaps() {
     // Test iterating.
     $count = 0;
     foreach ($typed_data as $item) {
-      $this->assertTrue($item instanceof \Drupal\Core\TypedData\TypedDataInterface);
+      $this->assertTrue($item instanceof \Drupal\Core\TypedData\Plugin\DataType\Any);
       $count++;
     }
     $this->assertEqual($count, 3);
@@ -505,6 +505,9 @@ public function testTypedDataValidation() {
         'Range' => array('min' => 5),
       ),
     );
+    $integer = $this->typedData->create($definition, 7);
+    $this->assertTrue($integer instanceof \Drupal\Core\TypedData\ValidatableInterface);
+
     $violations = $this->typedData->create($definition, 10)->validate();
     $this->assertEqual($violations->count(), 0);
 
@@ -614,4 +617,46 @@ public function testTypedDataValidation() {
     $this->assertEqual($violations[0]->getInvalidValue(), 'string');
     $this->assertIdentical($violations[0]->getPropertyPath(), '0.value');
   }
+
+  /**
+   * Tests typed data contexts.
+   */
+  function testTypedDataContext() {
+    // Test working with a simple map.
+    $value = array(
+      'one' => 'ett',
+      'two' => 'två',
+      'three' => 'tre',
+    );
+    $typed_data = $this->createTypedData(array(
+      'type' => 'map',
+    ), $value);
+
+    $this->assertTrue($typed_data instanceof \Drupal\Core\TypedData\ContextAwareInterface);
+
+    $item = $typed_data->get('one');
+    $this->assertEqual($item->getName(), 'one');
+    $this->assertEqual($item->getPropertyPath(), 'one');
+    $this->assertTrue($item->getParent() instanceof \Drupal\Core\TypedData\Plugin\DataType\Map);
+    $this->assertTrue($item->getRoot() instanceof \Drupal\Core\TypedData\Plugin\DataType\Map);
+  }
+
+  /**
+   * Tests the typed data manager.
+   */
+  function testTypedDataManager() {
+    // Test working with a simple map.
+    $value = array(
+      'one' => 'första',
+      'two' => 'andra',
+      'three' => 'tredje',
+    );
+    $typed_data = $this->createTypedData(array(
+      'type' => 'map',
+    ), $value);
+
+    $item = $this->typedData->getPropertyInstance($typed_data, 'two', 'prototyped value');
+    $this->assertTrue($item instanceof \Drupal\Core\TypedData\Plugin\DataType\Any);
+    $this->assertEqual($item->getValue(), 'prototyped value');
+  }
 }
diff --git a/core/modules/text/lib/Drupal/text/Plugin/field/field_type/TextItemBase.php b/core/modules/text/lib/Drupal/text/Plugin/field/field_type/TextItemBase.php
index 80c93b3..9d8ef70 100644
--- a/core/modules/text/lib/Drupal/text/Plugin/field/field_type/TextItemBase.php
+++ b/core/modules/text/lib/Drupal/text/Plugin/field/field_type/TextItemBase.php
@@ -100,7 +100,7 @@ public function prepareCache() {
       $itemBC = $this->getValue();
       $langcode = $this->getParent()->getParent()->language()->id;
       $this->set('safe_value', text_sanitize($this->getInstance()->settings['text_processing'], $langcode, $itemBC, 'value'));
-      if ($this->getType() == 'field_item:text_with_summary') {
+      if ($this instanceof TextWithSummaryItem) {
         $this->set('safe_summary', text_sanitize($this->getInstance()->settings['text_processing'], $langcode, $itemBC, 'summary'));
       }
     }
diff --git a/core/modules/text/lib/Drupal/text/TextProcessed.php b/core/modules/text/lib/Drupal/text/TextProcessed.php
index 9a1910f..446a005 100644
--- a/core/modules/text/lib/Drupal/text/TextProcessed.php
+++ b/core/modules/text/lib/Drupal/text/TextProcessed.php
@@ -7,7 +7,6 @@
 
 namespace Drupal\text;
 
-use Drupal\Core\TypedData\TypedDataInterface;
 use Drupal\Core\TypedData\TypedData;
 use Drupal\Core\TypedData\ReadOnlyException;
 use InvalidArgumentException;
@@ -37,7 +36,7 @@ class TextProcessed extends TypedData {
   /**
    * Overrides TypedData::__construct().
    */
-  public function __construct(array $definition, $name = NULL, TypedDataInterface $parent = NULL) {
+  public function __construct(array $definition, $name = NULL, $parent = NULL) {
     parent::__construct($definition, $name, $parent);
 
     if (!isset($definition['settings']['text source'])) {
@@ -48,7 +47,7 @@ public function __construct(array $definition, $name = NULL, TypedDataInterface
   /**
    * Overrides TypedData::setContext().
    */
-  public function setContext($name = NULL, TypedDataInterface $parent = NULL) {
+  public function setContext($name = NULL, $parent = NULL) {
     parent::setContext($name, $parent);
     if (isset($parent)) {
       $this->text = $parent->get($this->definition['settings']['text source']);
diff --git a/core/modules/views_ui/lib/Drupal/views_ui/ViewUI.php b/core/modules/views_ui/lib/Drupal/views_ui/ViewUI.php
index 92fa27b..636f909 100644
--- a/core/modules/views_ui/lib/Drupal/views_ui/ViewUI.php
+++ b/core/modules/views_ui/lib/Drupal/views_ui/ViewUI.php
@@ -11,7 +11,6 @@
 use Drupal\Core\Entity\EntityStorageControllerInterface;
 use Drupal\views\ViewExecutable;
 use Drupal\Core\Database\Database;
-use Drupal\Core\TypedData\TypedDataInterface;
 use Drupal\Core\Session\AccountInterface;
 use Drupal\views\Plugin\views\query\Sql;
 use Drupal\views\Plugin\Core\Entity\View;
@@ -1081,13 +1080,6 @@ public function initTranslation($langcode) {
   }
 
   /**
-   * Implements \Drupal\Core\TypedData\TypedDataInterface::getType().
-   */
-  public function getType() {
-    return $this->storage->getType();
-  }
-
-  /**
    * Implements \Drupal\Core\TypedData\TypedDataInterface::getDefinition().
    */
   public function getDefinition() {
@@ -1095,77 +1087,42 @@ public function getDefinition() {
   }
 
   /**
-   * Implements \Drupal\Core\TypedData\TypedDataInterface::getValue().
-   */
-  public function getValue() {
-    return $this->storage->getValue();
-  }
-
-  /**
-   * Implements \Drupal\Core\TypedData\TypedDataInterface::setValue().
-   */
-  public function setValue($value, $notify = TRUE) {
-    return $this->storage->setValue($value, $notify);
-  }
-
-  /**
-   * Implements \Drupal\Core\TypedData\TypedDataInterface::getString().
-   */
-  public function getString() {
-    return $this->storage->getString();
-  }
-
-  /**
-   * Implements \Drupal\Core\TypedData\TypedDataInterface::getConstraints().
-   */
-  public function getConstraints() {
-    return $this->storage->getConstraints();
-  }
-
-  /**
-   * Implements \Drupal\Core\TypedData\TypedDataInterface::validate().
-   */
-  public function validate() {
-    return $this->storage->validate();
-  }
-
-  /**
-   * Implements \Drupal\Core\TypedData\TypedDataInterface::getName().
+   * {@inheritdoc}
    */
   public function getName() {
     return $this->storage->getName();
   }
 
   /**
-   * Implements \Drupal\Core\TypedData\TypedDataInterface::getRoot().
+   * {@inheritdoc}
    */
   public function getRoot() {
     return $this->storage->getRoot();
   }
 
   /**
-   * Implements \Drupal\Core\TypedData\TypedDataInterface::getPropertyPath().
+   * {@inheritdoc}
    */
   public function getPropertyPath() {
     return $this->storage->getPropertyPath();
   }
 
   /**
-   * Implements \Drupal\Core\TypedData\TypedDataInterface::getParent().
+   * {@inheritdoc}
    */
   public function getParent() {
     return $this->storage->getParent();
   }
 
   /**
-   * Implements \Drupal\Core\TypedData\TypedDataInterface::setContext().
+   * {@inheritdoc}
    */
-  public function setContext($name = NULL, TypedDataInterface $parent = NULL) {
+  public function setContext($name = NULL, $parent = NULL) {
     return $this->storage->setContext($name, $parent);
   }
 
   /**
-   * Implements \Drupal\Core\TypedData\TypedDataInterface::onChange().
+   * {@inheritdoc}
    */
   public function onChange($property_name) {
     $this->storage->onChange($property_name);
