diff --git a/core/lib/Drupal/Core/Config/Entity/ConfigEntityBase.php b/core/lib/Drupal/Core/Config/Entity/ConfigEntityBase.php
index b39ff27..d5421b9 100644
--- a/core/lib/Drupal/Core/Config/Entity/ConfigEntityBase.php
+++ b/core/lib/Drupal/Core/Config/Entity/ConfigEntityBase.php
@@ -8,7 +8,7 @@
 namespace Drupal\Core\Config\Entity;
 
 use Drupal\Core\Entity\Entity;
-use Drupal\Core\TypedData\ContextAwareInterface;
+use Drupal\Core\TypedData\TypedDataInterface;
 
 /**
  * Defines a base configuration entity class.
@@ -178,37 +178,37 @@ public function getOriginalEntity() {
   }
 
   /**
-   * Implements \Drupal\Core\TypedData\ContextAwareInterface::getName().
+   * Implements \Drupal\Core\TypedData\TypedDataInterface::getName().
    */
   public function getName() {
     return NULL;
   }
 
   /**
-   * Implements \Drupal\Core\TypedData\ContextAwareInterface::getRoot().
+   * Implements \Drupal\Core\TypedData\TypedDataInterface::getRoot().
    */
   public function getRoot() {
     return $this;
   }
 
   /**
-   * Implements \Drupal\Core\TypedData\ContextAwareInterface::getPropertyPath().
+   * Implements \Drupal\Core\TypedData\TypedDataInterface::getPropertyPath().
    */
   public function getPropertyPath() {
     return '';
   }
 
   /**
-   * Implements \Drupal\Core\TypedData\ContextAwareInterface::getParent().
+   * Implements \Drupal\Core\TypedData\TypedDataInterface::getParent().
    */
   public function getParent() {
     return NULL;
   }
 
   /**
-   * Implements \Drupal\Core\TypedData\ContextAwareInterface::setContext().
+   * Implements \Drupal\Core\TypedData\TypedDataInterface::setContext().
    */
-  public function setContext($name = NULL, ContextAwareInterface $parent = NULL) {
+  public function setContext($name = NULL, TypedDataInterface $parent = NULL) {
     // As entities are always the root of the tree, we do not need to set any
     // context.
   }
diff --git a/core/lib/Drupal/Core/Config/Schema/Element.php b/core/lib/Drupal/Core/Config/Schema/Element.php
index efe7147..d4e29db 100644
--- a/core/lib/Drupal/Core/Config/Schema/Element.php
+++ b/core/lib/Drupal/Core/Config/Schema/Element.php
@@ -7,12 +7,12 @@
 
 namespace Drupal\Core\Config\Schema;
 
-use Drupal\Core\TypedData\ContextAwareTypedData;
+use Drupal\Core\TypedData\TypedData;
 
 /**
  * Defines a generic configuration element.
  */
-abstract class Element extends ContextAwareTypedData {
+abstract class Element extends TypedData {
 
   /**
    * The configuration value.
diff --git a/core/lib/Drupal/Core/Config/Schema/Mapping.php b/core/lib/Drupal/Core/Config/Schema/Mapping.php
index c09d9ad..e958f07 100644
--- a/core/lib/Drupal/Core/Config/Schema/Mapping.php
+++ b/core/lib/Drupal/Core/Config/Schema/Mapping.php
@@ -9,6 +9,7 @@
 
 use Drupal\Component\Utility\NestedArray;
 use Drupal\Core\TypedData\ComplexDataInterface;
+use Drupal\Core\TypedData\TypedDataInterface;
 use \InvalidArgumentException;
 
 /**
@@ -122,4 +123,14 @@ public function isEmpty() {
     return empty($this->value);
   }
 
+  /**
+   * 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/Entity.php b/core/lib/Drupal/Core/Entity/Entity.php
index fe00ef3..0b976c5 100644
--- a/core/lib/Drupal/Core/Entity/Entity.php
+++ b/core/lib/Drupal/Core/Entity/Entity.php
@@ -9,7 +9,7 @@
 
 use Drupal\Component\Uuid\Uuid;
 use Drupal\Core\Language\Language;
-use Drupal\Core\TypedData\ContextAwareInterface;
+use Drupal\Core\TypedData\TypedDataInterface;
 use IteratorAggregate;
 
 /**
@@ -251,6 +251,7 @@ public function isEmpty() {
   public function getIterator() {
     // @todo: Replace by EntityNG implementation once all entity types have been
     // converted to use the entity field API.
+    return new \ArrayIterator(array());
   }
 
   /**
@@ -406,37 +407,103 @@ public function getOriginalEntity() {
   }
 
   /**
-   * Implements \Drupal\Core\TypedData\ContextAwareInterface::getName().
+   * Implements \Drupal\Core\TypedData\TypedDataInterface::getType().
+   */
+  public function getType() {
+    // @todo: Incorporate the entity type here by making entities proper
+    // typed data. See http://drupal.org/node/1868004.
+    return 'entity';
+  }
+
+  /**
+   * Implements \Drupal\Core\TypedData\TypedDataInterface::getDefinition().
+   */
+  public function getDefinition() {
+    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().
+   */
+  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().
+   */
+  public function validate() {
+    // @todo: Implement by making entities proper typed data. See
+    // http://drupal.org/node/1868004.
+  }
+
+  /**
+   * Implements \Drupal\Core\TypedData\ComplexDataInterface::onChange().
+   */
+  public function onChange($property_name) {
+    // Nothing to do.
+  }
+
+  /**
+   * Implements \Drupal\Core\TypedData\TypedDataInterface::getName().
    */
   public function getName() {
     return NULL;
   }
 
   /**
-   * Implements \Drupal\Core\TypedData\ContextAwareInterface::getRoot().
+   * Implements \Drupal\Core\TypedData\TypedDataInterface::getRoot().
    */
   public function getRoot() {
     return $this;
   }
 
   /**
-   * Implements \Drupal\Core\TypedData\ContextAwareInterface::getPropertyPath().
+   * Implements \Drupal\Core\TypedData\TypedDataInterface::getPropertyPath().
    */
   public function getPropertyPath() {
     return '';
   }
 
   /**
-   * Implements \Drupal\Core\TypedData\ContextAwareInterface::getParent().
+   * Implements \Drupal\Core\TypedData\TypedDataInterface::getParent().
    */
   public function getParent() {
     return NULL;
   }
 
   /**
-   * Implements \Drupal\Core\TypedData\ContextAwareInterface::setContext().
+   * Implements \Drupal\Core\TypedData\TypedDataInterface::setContext().
    */
-  public function setContext($name = NULL, ContextAwareInterface $parent = NULL) {
+  public function setContext($name = NULL, TypedDataInterface $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 a23f7e4..497621e 100644
--- a/core/lib/Drupal/Core/Entity/EntityBCDecorator.php
+++ b/core/lib/Drupal/Core/Entity/EntityBCDecorator.php
@@ -9,7 +9,7 @@
 
 use IteratorAggregate;
 use Drupal\Core\Entity\EntityInterface;
-use Drupal\Core\TypedData\ContextAwareInterface;
+use Drupal\Core\TypedData\TypedDataInterface;
 
 /**
  * Provides backwards compatible (BC) access to entity fields.
@@ -422,6 +422,55 @@ public function getTranslation($langcode, $strict = TRUE) {
   /**
    * Forwards the call to the decorated entity.
    */
+  public function getType() {
+    return $this->decorated->getType();
+  }
+
+  /**
+   * Forwards the call to the decorated entity.
+   */
+  public function getDefinition() {
+    return $this->decorated->getDefinition();
+  }
+
+  /**
+   * Forwards the call to the decorated entity.
+   */
+  public function getValue() {
+    return $this->decorated->getValue();
+  }
+
+  /**
+   * Forwards the call to the decorated entity.
+   */
+  public function setValue($value, $notify = TRUE) {
+    return $this->decorated->setValue($value);
+  }
+
+  /**
+   * Forwards the call to the decorated entity.
+   */
+  public function getString() {
+    return $this->decorated->getString();
+  }
+
+  /**
+   * Forwards the call to the decorated entity.
+   */
+  public function getConstraints() {
+    return $this->decorated->getConstraints();
+  }
+
+  /**
+   * Forwards the call to the decorated entity.
+   */
+  public function validate() {
+    return $this->decorated->validate();
+  }
+
+  /**
+   * Forwards the call to the decorated entity.
+   */
   public function getName() {
     return $this->decorated->getName();
   }
@@ -450,7 +499,7 @@ public function getParent() {
   /**
    * Forwards the call to the decorated entity.
    */
-  public function setContext($name = NULL, ContextAwareInterface $parent = NULL) {
+  public function setContext($name = NULL, TypedDataInterface $parent = NULL) {
     $this->decorated->setContext($name, $parent);
   }
 
@@ -460,4 +509,11 @@ public function setContext($name = NULL, ContextAwareInterface $parent = NULL) {
   public function getExportProperties() {
     $this->decorated->getExportProperties();
   }
+
+  /**
+   * Forwards the call to the decorated entity.
+   */
+  public function onChange($property_name) {
+    $this->decorated->onChange($property_name, $property, $new_value);
+  }
 }
diff --git a/core/lib/Drupal/Core/Entity/EntityInterface.php b/core/lib/Drupal/Core/Entity/EntityInterface.php
index 34038e9..2a8444a 100644
--- a/core/lib/Drupal/Core/Entity/EntityInterface.php
+++ b/core/lib/Drupal/Core/Entity/EntityInterface.php
@@ -8,7 +8,6 @@
 namespace Drupal\Core\Entity;
 
 use Drupal\Core\TypedData\AccessibleInterface;
-use Drupal\Core\TypedData\ContextAwareInterface;
 use Drupal\Core\TypedData\ComplexDataInterface;
 use Drupal\Core\TypedData\TranslatableInterface;
 
@@ -28,7 +27,7 @@
  * @see \Drupal\Core\TypedData\TypedDataManager
  * @see \Drupal\Core\Field\FieldInterface
  */
-interface EntityInterface extends ContextAwareInterface, ComplexDataInterface, AccessibleInterface, TranslatableInterface {
+interface EntityInterface extends ComplexDataInterface, AccessibleInterface, TranslatableInterface {
 
   /**
    * Returns the entity identifier (the entity's machine name or numeric ID).
diff --git a/core/lib/Drupal/Core/Entity/EntityNG.php b/core/lib/Drupal/Core/Entity/EntityNG.php
index 70ac362..14403bb 100644
--- a/core/lib/Drupal/Core/Entity/EntityNG.php
+++ b/core/lib/Drupal/Core/Entity/EntityNG.php
@@ -8,7 +8,6 @@
 namespace Drupal\Core\Entity;
 
 use Drupal\Core\Language\Language;
-use Drupal\Core\TypedData\ContextAwareInterface;
 use Drupal\Core\TypedData\TypedDataInterface;
 use Drupal\Component\Uuid\Uuid;
 use ArrayIterator;
@@ -170,6 +169,7 @@ protected function getTranslatedField($property_name, $langcode) {
         if (isset($this->values[$property_name][$langcode])) {
           $value = $this->values[$property_name][$langcode];
         }
+        // @todo: Make entities implement the TypedDataInterface.
         $this->fields[$property_name][$langcode] = typed_data()->getPropertyInstance($this, $property_name, $value);
       }
     }
@@ -318,9 +318,7 @@ public function getTranslation($langcode, $strict = TRUE) {
     );
     $translation = typed_data()->create($translation_definition, $fields);
     $translation->setStrictMode($strict);
-    if ($translation instanceof ContextAwareInterface) {
-      $translation->setContext('@' . $langcode, $this);
-    }
+    $translation->setContext('@' . $langcode, $this);
     return $translation;
   }
 
@@ -435,7 +433,7 @@ public function &__get($name) {
    */
   public function __set($name, $value) {
     // Support setting values via property objects.
-    if ($value instanceof TypedDataInterface) {
+    if ($value instanceof TypedDataInterface && !$value instanceof EntityInterface) {
       $value = $value->getValue();
     }
     // If this is an entity field, handle it accordingly. We first check whether
@@ -508,9 +506,7 @@ public function __clone() {
     foreach ($this->fields as $name => $properties) {
       foreach ($properties as $langcode => $property) {
         $this->fields[$name][$langcode] = clone $property;
-        if ($property instanceof ContextAwareInterface) {
-          $this->fields[$name][$langcode]->setContext($name, $this);
-        }
+        $this->fields[$name][$langcode]->setContext($name, $this);
       }
     }
   }
diff --git a/core/lib/Drupal/Core/Entity/Field/FieldInterface.php b/core/lib/Drupal/Core/Entity/Field/FieldInterface.php
index 81f3828..7b1d235 100644
--- a/core/lib/Drupal/Core/Entity/Field/FieldInterface.php
+++ b/core/lib/Drupal/Core/Entity/Field/FieldInterface.php
@@ -8,9 +8,7 @@
 namespace Drupal\Core\Entity\Field;
 
 use Drupal\Core\TypedData\AccessibleInterface;
-use Drupal\Core\TypedData\ContextAwareInterface;
 use Drupal\Core\TypedData\ListInterface;
-use Drupal\Core\TypedData\TypedDataInterface;
 
 /**
  * Interface for fields, being lists of field items.
@@ -27,7 +25,7 @@
  * When implementing this interface which extends Traversable, make sure to list
  * IteratorAggregate or Iterator before this interface in the implements clause.
  */
-interface FieldInterface extends ListInterface, AccessibleInterface, ContextAwareInterface, TypedDataInterface {
+interface FieldInterface extends ListInterface, AccessibleInterface {
 
   /**
    * Gets a property object from the first field item.
diff --git a/core/lib/Drupal/Core/Entity/Field/FieldItemBase.php b/core/lib/Drupal/Core/Entity/Field/FieldItemBase.php
index 62edc8d..ce1a98d 100644
--- a/core/lib/Drupal/Core/Entity/Field/FieldItemBase.php
+++ b/core/lib/Drupal/Core/Entity/Field/FieldItemBase.php
@@ -7,13 +7,9 @@
 
 namespace Drupal\Core\Entity\Field;
 
-use Drupal\Core\TypedData\ContextAwareTypedData;
-use Drupal\Core\TypedData\ContextAwareInterface;
+use Drupal\Core\TypedData\Type\Map;
 use Drupal\Core\TypedData\TypedDataInterface;
 use Drupal\user;
-use ArrayIterator;
-use IteratorAggregate;
-use InvalidArgumentException;
 
 /**
  * An entity field item.
@@ -23,62 +19,7 @@
  *
  * @see \Drupal\Core\Entity\Field\FieldItemInterface
  */
-abstract class FieldItemBase extends ContextAwareTypedData implements IteratorAggregate, FieldItemInterface {
-
-  /**
-   * The array of properties, each implementing the TypedDataInterface.
-   *
-   * Field objects are instantiated during object construction and cannot be
-   * replaced by others, so computed properties can safely store references on
-   * other properties.
-   *
-   * @var array
-   */
-  protected $properties = array();
-
-  /**
-   * Holds any non-property values that get set on the object.
-   *
-   * @todo: Remove or refactor once EntityNG conversion is complete.
-   *
-   * @var array
-   */
-  protected $extraValues = array();
-
-  /**
-   * Overrides ContextAwareTypedData::__construct().
-   */
-  public function __construct(array $definition, $name = NULL, ContextAwareInterface $parent = NULL) {
-    parent::__construct($definition, $name, $parent);
-
-    // Initialize all property objects, but postpone the creating of computed
-    // properties to a second step. That way computed properties can safely get
-    // references on non-computed properties during construction.
-    $step2 = array();
-    foreach ($this->getPropertyDefinitions() as $name => $definition) {
-      if (empty($definition['computed'])) {
-        $this->properties[$name] = typed_data()->getPropertyInstance($this, $name);
-      }
-      else {
-        $step2[] = $name;
-      }
-    }
-
-    foreach ($step2 as $name) {
-      $this->properties[$name] = typed_data()->getPropertyInstance($this, $name);
-    }
-  }
-
-  /**
-   * Overrides \Drupal\Core\TypedData\TypedData::getValue().
-   */
-  public function getValue() {
-    $values = array();
-    foreach ($this->getProperties() as $name => $property) {
-      $values[$name] = $property->getValue();
-    }
-    return $values + $this->extraValues;
-  }
+abstract class FieldItemBase extends Map implements FieldItemInterface {
 
   /**
    * Overrides \Drupal\Core\TypedData\TypedData::setValue().
@@ -86,66 +27,44 @@ public function getValue() {
    * @param array|null $values
    *   An array of property values.
    */
-  public function setValue($values) {
+  public function setValue($values, $notify = TRUE) {
     // Treat the values as property value of the first property, if no array is
     // given.
     if (!is_array($values)) {
-      $keys = array_keys($this->properties);
+      $keys = array_keys($this->getPropertyDefinitions());
       $values = array($keys[0] => $values);
     }
-
-    foreach ($this->properties as $name => $property) {
-      if (isset($values[$name])) {
-        $property->setValue($values[$name]);
-      }
-      else {
-        $property->setValue(NULL);
-      }
-      unset($values[$name]);
-    }
-    // @todo: Throw an exception for invalid values once conversion is
-    // totally completed.
-    $this->extraValues = $values;
+    parent::setValue($values, $notify);
   }
 
   /**
-   * Overrides \Drupal\Core\TypedData\TypedData::getString().
+   * Implements \Drupal\Core\Entity\Field\FieldItemInterface::__get().
    */
-  public function getString() {
-    $strings = array();
-    foreach ($this->getProperties() as $property) {
-      $strings[] = $property->getString();
+  public function __get($name) {
+    // Directly return the plain value, if we have any.
+    if (isset($this->values[$name]) || array_key_exists($name, $this->values)) {
+      return $this->values[$name];
     }
-    return implode(', ', array_filter($strings));
-  }
-
-  /**
-   * Implements \Drupal\Core\TypedData\ComplexDataInterface::get().
-   */
-  public function get($property_name) {
-    if (!isset($this->properties[$property_name])) {
-      throw new InvalidArgumentException('Field ' . check_plain($property_name) . ' is unknown.');
+    else {
+      // Go via the property object, so e.g. computed properties are computed.
+      return $this->get($name)->getValue();
     }
-    return $this->properties[$property_name];
   }
 
   /**
-   * Implements \Drupal\Core\TypedData\ComplexDataInterface::set().
+   * Overrides \Drupal\Core\TypedData\Type\Map::set().
    */
   public function set($property_name, $value) {
-    $this->get($property_name)->setValue($value);
-  }
-
-  /**
-   * Implements \Drupal\Core\Entity\Field\FieldItemInterface::__get().
-   */
-  public function __get($name) {
-    if (isset($this->properties[$name])) {
-      return $this->properties[$name]->getValue();
+    if (isset($this->properties[$property_name])) {
+      $this->properties[$property_name]->setValue($value);
     }
-    // The property is unknown, so try to get it from the extra values.
-    elseif (isset($this->extraValues[$name])) {
-      return $this->extraValues[$name];
+    else {
+      // Notify the parent of any changes to be made.
+      if (isset($this->parent)) {
+        $this->parent->onChange($this->name);
+      }
+      // Just set the plain value, which allows adding a new entry to the map.
+      $this->values[$property_name] = $value;
     }
   }
 
@@ -153,105 +72,38 @@ public function __get($name) {
    * Implements \Drupal\Core\Entity\Field\FieldItemInterface::__set().
    */
   public function __set($name, $value) {
-    // Support setting values via property objects.
-    if ($value instanceof TypedDataInterface) {
+    // 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 \Drupal\Core\Entity\EntityInterface)) {
       $value = $value->getValue();
     }
-    if (isset($this->properties[$name])) {
-      $this->properties[$name]->setValue($value);
-    }
-    else {
-      // The property is unknown, so set it to the extra values.
-      $this->extraValues[$name] = $value;
-    }
+    $this->set($name, $value);
   }
 
   /**
    * Implements \Drupal\Core\Entity\Field\FieldItemInterface::__isset().
    */
   public function __isset($name) {
-    return isset($this->properties[$name]) && $this->properties[$name]->getValue() !== NULL;
+    return isset($this->values[$name]) || (isset($this->properties[$name]) && $this->properties[$name]->getValue() !== NULL);
   }
 
   /**
    * Implements \Drupal\Core\Entity\Field\FieldItemInterface::__unset().
    */
   public function __unset($name) {
-    if (isset($this->properties[$name])) {
-      $this->properties[$name]->setValue(NULL);
-    }
-  }
-
-  /**
-   * Implements \Drupal\Core\TypedData\ComplexDataInterface::getProperties().
-   */
-  public function getProperties($include_computed = FALSE) {
-    $properties = array();
-    foreach ($this->getPropertyDefinitions() as $name => $definition) {
-      if ($include_computed || empty($definition['computed'])) {
-        $properties[$name] = $this->properties[$name];
-      }
-    }
-    return $properties;
-  }
-
-  /**
-   * Implements \Drupal\Core\TypedData\ComplexDataInterface::getPropertyValues().
-   */
-  public function getPropertyValues() {
-    return $this->getValue();
-  }
-
-  /**
-   * Implements \Drupal\Core\TypedData\ComplexDataInterface::setPropertyValues().
-   */
-  public function setPropertyValues($values) {
-    foreach ($values as $name => $value) {
-      $this->get($name)->setValue($value);
-    }
-  }
-
-  /**
-   * Implements \IteratorAggregate::getIterator().
-   */
-  public function getIterator() {
-    return new ArrayIterator($this->getProperties());
-  }
-
-  /**
-   * 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::isEmpty().
-   */
-  public function isEmpty() {
-    foreach ($this->getProperties() as $property) {
-      if ($property->getValue() !== NULL) {
-        return FALSE;
-      }
-    }
-    return TRUE;
+    $this->set($name, NULL);
   }
 
   /**
-   * Magic method: Implements a deep clone.
+   * Overrides \Drupal\Core\TypedData\Map::onChange().
    */
-  public function __clone() {
-    foreach ($this->properties as $name => $property) {
-      $this->properties[$name] = clone $property;
-      if ($property instanceof ContextAwareInterface) {
-        $this->properties[$name]->setContext($name, $this);
-      }
+  public function onChange($property_name) {
+    // Notify the parent of changes.
+    if (isset($this->parent)) {
+      $this->parent->onChange($this->name);
     }
+    // Remove the plain value, such that any further __get() calls go via the
+    // updated property object.
+    unset($this->values[$property_name]);
   }
 }
\ No newline at end of file
diff --git a/core/lib/Drupal/Core/Entity/Field/FieldItemInterface.php b/core/lib/Drupal/Core/Entity/Field/FieldItemInterface.php
index d115be5..31adec9 100644
--- a/core/lib/Drupal/Core/Entity/Field/FieldItemInterface.php
+++ b/core/lib/Drupal/Core/Entity/Field/FieldItemInterface.php
@@ -8,8 +8,6 @@
 namespace Drupal\Core\Entity\Field;
 
 use Drupal\Core\TypedData\ComplexDataInterface;
-use Drupal\Core\TypedData\ContextAwareInterface;
-use Drupal\Core\TypedData\TypedDataInterface;
 
 /**
  * Interface for entity field items.
@@ -23,7 +21,7 @@
  * @see \Drupal\Core\Entity\Field\FieldInterface
  * @see \Drupal\Core\Entity\Field\FieldItemBase
  */
-interface FieldItemInterface extends ComplexDataInterface, ContextAwareInterface, TypedDataInterface {
+interface FieldItemInterface extends ComplexDataInterface {
 
   /**
    * Magic method: Gets a property value.
diff --git a/core/lib/Drupal/Core/Entity/Field/Type/EntityReferenceItem.php b/core/lib/Drupal/Core/Entity/Field/Type/EntityReferenceItem.php
index 695a7ca..6971e39 100644
--- a/core/lib/Drupal/Core/Entity/Field/Type/EntityReferenceItem.php
+++ b/core/lib/Drupal/Core/Entity/Field/Type/EntityReferenceItem.php
@@ -8,6 +8,7 @@
 namespace Drupal\Core\Entity\Field\Type;
 
 use Drupal\Core\Entity\Field\FieldItemBase;
+use Drupal\Core\TypedData\TypedDataInterface;
 
 /**
  * Defines the 'entity_reference' entity field item.
@@ -27,6 +28,16 @@ class EntityReferenceItem extends FieldItemBase {
   static $propertyDefinitions;
 
   /**
+   * Overrides \Drupal\Core\TypedData\TypedData::__construct().
+   */
+  public function __construct(array $definition, $name = NULL, TypedDataInterface $parent = NULL) {
+    $this->definition = $definition;
+    $this->setContext($name, $parent);
+    // Initialize the entity property by default.
+    $this->properties['entity'] = typed_data()->getPropertyInstance($this, 'entity');
+  }
+
+  /**
    * Implements \Drupal\Core\TypedData\ComplexDataInterface::getPropertyDefinitions().
    */
   public function getPropertyDefinitions() {
@@ -59,40 +70,6 @@ public function getPropertyDefinitions() {
   }
 
   /**
-   * Overrides \Drupal\Core\Entity\Field\FieldItemBase::setValue().
-   */
-  public function setValue($values) {
-    // Treat the values as property value of the entity field, if no array
-    // is given. That way we support setting the field by entity ID or object.
-    if (!is_array($values)) {
-      $values = array('entity' => $values);
-    }
-
-    // Entity is computed out of the ID, so we only need to update the ID. Only
-    // set the entity field if no ID is given.
-    if (isset($values['target_id'])) {
-      $this->properties['target_id']->setValue($values['target_id']);
-    }
-    elseif (isset($values['entity'])) {
-      $this->properties['entity']->setValue($values['entity']);
-    }
-    else {
-      $this->properties['entity']->setValue(NULL);
-    }
-    unset($values['entity'], $values['target_id']);
-    if ($values) {
-      throw new \InvalidArgumentException('Property ' . key($values) . ' is unknown.');
-    }
-  }
-
-  /**
-   * Overrides \Drupal\Core\Entity\Field\FieldItemBase::__set().
-   */
-  public function __set($name, $value) {
-    parent::__set($name, $value);
-  }
-
-  /**
    * Overrides \Drupal\Core\Entity\Field\FieldItemBase::__get().
    */
   public function __get($name) {
@@ -116,4 +93,32 @@ public function __isset($property_name) {
     return parent::__isset($property_name);
   }
 
+  /**
+   * Overrides \Drupal\Core\Entity\Field\FieldItemBase::get().
+   */
+  public function setValue($values, $notify = TRUE) {
+    // Treat the values as property value of the first property, if no array is
+    // given.
+    if (!is_array($values)) {
+      $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, except of 'entity'.
+    foreach ($this->properties as $name => $property) {
+      if ($name != 'entity') {
+        $value = NULL;
+        if (isset($values[$name])) {
+          $value = $values[$name];
+        }
+        $property->setValue($value, FALSE);
+      }
+    }
+  }
 }
diff --git a/core/lib/Drupal/Core/Entity/Field/Type/EntityTranslation.php b/core/lib/Drupal/Core/Entity/Field/Type/EntityTranslation.php
index 97a5627..4765a54 100644
--- a/core/lib/Drupal/Core/Entity/Field/Type/EntityTranslation.php
+++ b/core/lib/Drupal/Core/Entity/Field/Type/EntityTranslation.php
@@ -9,8 +9,9 @@
 
 use Drupal\Core\TypedData\AccessibleInterface;
 use Drupal\Core\TypedData\ComplexDataInterface;
-use Drupal\Core\TypedData\ContextAwareTypedData;
+use Drupal\Core\TypedData\TypedData;
 use ArrayIterator;
+use Drupal\Core\TypedData\TypedDataInterface;
 use IteratorAggregate;
 use InvalidArgumentException;
 
@@ -20,7 +21,7 @@
  * Via this object translated entity fields may be read and updated in the same
  * way as untranslatable entity fields on the entity object.
  */
-class EntityTranslation extends ContextAwareTypedData implements IteratorAggregate, AccessibleInterface, ComplexDataInterface {
+class EntityTranslation extends TypedData implements IteratorAggregate, AccessibleInterface, ComplexDataInterface {
 
   /**
    * The array of translated fields, each being an instance of
@@ -71,7 +72,11 @@ public function getValue() {
   /**
    * Overrides \Drupal\Core\TypedData\TypedData::setValue().
    */
-  public function setValue($values) {
+  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);
+    }
     $this->fields = $values;
   }
 
@@ -193,6 +198,16 @@ public function isEmpty() {
   }
 
   /**
+   * 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);
+    }
+  }
+
+  /**
    * Implements \Drupal\Core\TypedData\AccessibleInterface::access().
    */
   public function access($operation = 'view', \Drupal\user\Plugin\Core\Entity\User $account = NULL) {
diff --git a/core/lib/Drupal/Core/Entity/Field/Type/EntityWrapper.php b/core/lib/Drupal/Core/Entity/Field/Type/EntityWrapper.php
index fdd4d38..10492e6 100644
--- a/core/lib/Drupal/Core/Entity/Field/Type/EntityWrapper.php
+++ b/core/lib/Drupal/Core/Entity/Field/Type/EntityWrapper.php
@@ -8,10 +8,8 @@
 namespace Drupal\Core\Entity\Field\Type;
 
 use Drupal\Core\Entity\EntityInterface;
-use Drupal\Core\Entity\EntityNG;
 use Drupal\Core\TypedData\ComplexDataInterface;
-use Drupal\Core\TypedData\ContextAwareInterface;
-use Drupal\Core\TypedData\ContextAwareTypedData;
+use Drupal\Core\TypedData\TypedData;
 use Drupal\Core\TypedData\TypedDataInterface;
 use ArrayIterator;
 use IteratorAggregate;
@@ -37,7 +35,7 @@
  *  - id source: If used as computed property, the ID property used to load
  *    the entity object.
  */
-class EntityWrapper extends ContextAwareTypedData implements IteratorAggregate, ComplexDataInterface {
+class EntityWrapper extends TypedData implements IteratorAggregate, ComplexDataInterface {
 
   /**
    * The referenced entity type.
@@ -61,9 +59,9 @@ class EntityWrapper extends ContextAwareTypedData implements IteratorAggregate,
   protected $newEntity;
 
   /**
-   * Overrides ContextAwareTypedData::__construct().
+   * Overrides TypedData::__construct().
    */
-  public function __construct(array $definition, $name = NULL, ContextAwareInterface $parent = NULL) {
+  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;
   }
@@ -75,18 +73,10 @@ public function getValue() {
     if (isset($this->newEntity)) {
       return $this->newEntity;
     }
-    $source = $this->getIdSource();
-    $id = $source ? $source->getValue() : $this->id;
-    return $id ? entity_load($this->entityType, $id) : NULL;
-  }
-
-  /**
-   * Helper to get the typed data object holding the source entity ID.
-   *
-   * @return \Drupal\Core\TypedData\TypedDataInterface|FALSE
-   */
-  protected function getIdSource() {
-    return !empty($this->definition['settings']['id source']) ? $this->parent->get($this->definition['settings']['id source']) : FALSE;
+    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;
   }
 
   /**
@@ -94,7 +84,7 @@ protected function getIdSource() {
    *
    * Both the entity ID and the entity object may be passed as value.
    */
-  public function setValue($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()) {
@@ -110,12 +100,15 @@ public function setValue($value) {
     elseif (isset($value) && !(is_scalar($value) && !empty($this->definition['constraints']['EntityType']))) {
       throw new InvalidArgumentException('Value is not a valid entity.');
     }
-    // Now update the value in the source or the local id property.
-    $source = $this->getIdSource();
-    if ($source) {
-      $source->setValue($value);
+    // Update the 'id source' property, if given.
+    if (!empty($this->definition['settings']['id source'])) {
+      $this->parent->__set($this->definition['settings']['id source'], $value);
     }
     else {
+      // Notify the parent of any changes to be made.
+      if ($notify && isset($this->parent)) {
+        $this->parent->onChange($this->name);
+      }
       $this->id = $value;
     }
   }
@@ -134,9 +127,7 @@ public function getString() {
    * Implements \IteratorAggregate::getIterator().
    */
   public function getIterator() {
-    // @todo: Remove check for EntityNG once all entity types are converted.
-    $entity = $this->getValue();
-    if ($entity && $entity instanceof EntityNG) {
+    if ($entity = $this->getValue()) {
       return $entity->getIterator();
     }
     return new ArrayIterator(array());
@@ -215,4 +206,14 @@ public function setPropertyValues($values) {
   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/Field/Type/Field.php b/core/lib/Drupal/Core/Entity/Field/Type/Field.php
index 305fc1f..8c5451a 100644
--- a/core/lib/Drupal/Core/Entity/Field/Type/Field.php
+++ b/core/lib/Drupal/Core/Entity/Field/Type/Field.php
@@ -9,7 +9,7 @@
 
 use Drupal\Core\Entity\Field\FieldInterface;
 use Drupal\user\Plugin\Core\Entity\User;
-use Drupal\Core\TypedData\ContextAwareInterface;
+use Drupal\Core\TypedData\TypedDataInterface;
 use Drupal\Core\TypedData\ItemList;
 
 /**
@@ -34,9 +34,9 @@ class Field extends ItemList implements FieldInterface {
   protected $list = array();
 
   /**
-   * Overrides ContextAwareTypedData::__construct().
+   * Overrides TypedData::__construct().
    */
-  public function __construct(array $definition, $name = NULL, ContextAwareInterface $parent = NULL) {
+  public function __construct(array $definition, $name = NULL, TypedDataInterface $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
@@ -66,7 +66,11 @@ public function getValue() {
   /**
    * Overrides \Drupal\Core\TypedData\ItemList::setValue().
    */
-  public function setValue($values) {
+  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;
     }
@@ -114,7 +118,7 @@ public function getPropertyDefinitions() {
    * Implements \Drupal\Core\Entity\Field\FieldInterface::__get().
    */
   public function __get($property_name) {
-    return $this->offsetGet(0)->get($property_name)->getValue();
+    return $this->offsetGet(0)->__get($property_name);
   }
 
   /**
diff --git a/core/lib/Drupal/Core/Entity/Field/Type/LanguageItem.php b/core/lib/Drupal/Core/Entity/Field/Type/LanguageItem.php
index b3765b1..4f16384 100644
--- a/core/lib/Drupal/Core/Entity/Field/Type/LanguageItem.php
+++ b/core/lib/Drupal/Core/Entity/Field/Type/LanguageItem.php
@@ -8,7 +8,7 @@
 namespace Drupal\Core\Entity\Field\Type;
 
 use Drupal\Core\Entity\Field\FieldItemBase;
-use InvalidArgumentException;
+use Drupal\Core\TypedData\TypedDataInterface;
 
 /**
  * Defines the 'language_field' entity field item.
@@ -25,6 +25,16 @@ class LanguageItem extends FieldItemBase {
   static $propertyDefinitions;
 
   /**
+   * Overrides \Drupal\Core\TypedData\TypedData::__construct().
+   */
+  public function __construct(array $definition, $name = NULL, TypedDataInterface $parent = NULL) {
+    $this->definition = $definition;
+    $this->setContext($name, $parent);
+    // Initialize the language property by default.
+    $this->properties['language'] = typed_data()->getPropertyInstance($this, 'language');
+  }
+
+  /**
    * Implements \Drupal\Core\TypedData\ComplexDataInterface::getPropertyDefinitions().
    */
   public function getPropertyDefinitions() {
@@ -47,30 +57,31 @@ public function getPropertyDefinitions() {
   }
 
   /**
-   * Overrides FieldItemBase::setValue().
+   * Overrides \Drupal\Core\Entity\Field\FieldItemBase::get().
    */
-  public function setValue($values) {
-    // Treat the values as property value of the object property, if no array
-    // is given. That way we support setting the field by language code or
-    // object.
+  public function setValue($values, $notify = TRUE) {
+    // Treat the values as property value of the first property, if no array is
+    // given.
     if (!is_array($values)) {
-      $values = array('language' => $values);
+      $keys = array_keys($this->getPropertyDefinitions());
+      $values = array($keys[0] => $values);
     }
 
-    // Language is computed out of the langcode, so we only need to update the
-    // langcode. Only set the language property if no langcode is given.
-    if (!empty($values['value'])) {
-      $this->properties['value']->setValue($values['value']);
+    // Notify the parent of any changes to be made.
+    if ($notify && isset($this->parent)) {
+      $this->parent->onChange($this->name);
     }
-    elseif (isset($values['language'])) {
-      $this->properties['language']->setValue($values['language']);
-    }
-    else {
-      $this->properties['language']->setValue(NULL);
-    }
-    unset($values['language'], $values['value']);
-    if ($values) {
-      throw new InvalidArgumentException('Property ' . key($values) . ' is unknown.');
+    $this->values = $values;
+
+    // Update any existing property objects, except of 'entity'.
+    foreach ($this->properties as $name => $property) {
+      if ($name != 'language') {
+        $value = NULL;
+        if (isset($values[$name])) {
+          $value = $values[$name];
+        }
+        $property->setValue($value, FALSE);
+      }
     }
   }
 }
diff --git a/core/lib/Drupal/Core/Plugin/Context/Context.php b/core/lib/Drupal/Core/Plugin/Context/Context.php
index e6d680f..9055d12 100644
--- a/core/lib/Drupal/Core/Plugin/Context/Context.php
+++ b/core/lib/Drupal/Core/Plugin/Context/Context.php
@@ -8,6 +8,7 @@
 namespace Drupal\Core\Plugin\Context;
 
 use Drupal\Component\Plugin\Context\Context as ComponentContext;
+use Drupal\Core\Entity\Field\Type\EntityWrapper;
 use Drupal\Core\TypedData\ComplexDataInterface;
 use Drupal\Core\TypedData\ListInterface;
 use Drupal\Core\TypedData\TypedDataInterface;
@@ -36,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->getType() == 'entity')) {
+    if ($typed_value instanceof TypedDataInterface && (!$is_complex || $typed_value instanceof EntityWrapper)) {
       return $typed_value->getValue();
     }
     return $typed_value;
diff --git a/core/lib/Drupal/Core/Plugin/Validation/Constraint/BundleConstraintValidator.php b/core/lib/Drupal/Core/Plugin/Validation/Constraint/BundleConstraintValidator.php
index d649ccf..0eb0edb 100644
--- a/core/lib/Drupal/Core/Plugin/Validation/Constraint/BundleConstraintValidator.php
+++ b/core/lib/Drupal/Core/Plugin/Validation/Constraint/BundleConstraintValidator.php
@@ -19,7 +19,8 @@ class BundleConstraintValidator extends ConstraintValidator {
    * Implements \Symfony\Component\Validator\ConstraintValidatorInterface::validate().
    */
   public function validate($typed_data, Constraint $constraint) {
-    $entity = isset($typed_data) ? $typed_data->getValue() : FALSE;
+    // If the entity is contained in a reference, unwrap it first.
+    $entity = isset($typed_data) && !($typed_data instanceof EntityInterface) ? $typed_data->getValue() : FALSE;
 
     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/Plugin/Validation/Constraint/EntityTypeConstraintValidator.php b/core/lib/Drupal/Core/Plugin/Validation/Constraint/EntityTypeConstraintValidator.php
index 1e1aba4..3020078 100644
--- a/core/lib/Drupal/Core/Plugin/Validation/Constraint/EntityTypeConstraintValidator.php
+++ b/core/lib/Drupal/Core/Plugin/Validation/Constraint/EntityTypeConstraintValidator.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\Core\Plugin\Validation\Constraint;
 
+use Drupal\Core\Entity\EntityInterface;
 use Symfony\Component\Validator\Constraint;
 use Symfony\Component\Validator\ConstraintValidator;
 
@@ -19,7 +20,8 @@ class EntityTypeConstraintValidator extends ConstraintValidator {
    * Implements \Symfony\Component\Validator\ConstraintValidatorInterface::validate().
    */
   public function validate($typed_data, Constraint $constraint) {
-    $entity = isset($typed_data) ? $typed_data->getValue() : FALSE;
+    // If the entity is contained in a reference, unwrap it first.
+    $entity = isset($typed_data) && !($typed_data instanceof EntityInterface) ? $typed_data->getValue() : FALSE;
 
     if (!empty($entity) && $entity->entityType() != $constraint->type) {
       $this->context->addViolation($constraint->message, array('%type' => $constraint->type));
diff --git a/core/lib/Drupal/Core/TypedData/ComplexDataInterface.php b/core/lib/Drupal/Core/TypedData/ComplexDataInterface.php
index 62f0363..e3a540b 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  {
+interface ComplexDataInterface extends Traversable, TypedDataInterface  {
 
   /**
    * Gets a property object.
@@ -120,4 +120,14 @@ public function getPropertyDefinitions();
    *   TRUE if the data structure is empty, FALSE otherwise.
    */
   public function isEmpty();
+
+  /**
+   * React to changes to a child property.
+   *
+   * Note that this is invoked before any changes are applied.
+   *
+   * @param $property_name
+   *   The name of the property which is changed.
+   */
+  public function onChange($property_name);
 }
diff --git a/core/lib/Drupal/Core/TypedData/ContextAwareInterface.php b/core/lib/Drupal/Core/TypedData/ContextAwareInterface.php
deleted file mode 100644
index d2b2d3b..0000000
--- a/core/lib/Drupal/Core/TypedData/ContextAwareInterface.php
+++ /dev/null
@@ -1,70 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\Core\TypedData\ContextAwareInterface.
- */
-
-namespace Drupal\Core\TypedData;
-
-/**
- * Interface for context aware data.
- */
-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\ContextAwareInterface $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, ContextAwareInterface $parent = NULL);
-}
diff --git a/core/lib/Drupal/Core/TypedData/ContextAwareTypedData.php b/core/lib/Drupal/Core/TypedData/ContextAwareTypedData.php
deleted file mode 100644
index 29d07cd..0000000
--- a/core/lib/Drupal/Core/TypedData/ContextAwareTypedData.php
+++ /dev/null
@@ -1,107 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\Core\TypedData\ContextAwareTypedData.
- */
-
-namespace Drupal\Core\TypedData;
-
-/**
- * An abstract base class for context aware typed data.
- *
- * This implementation requires parent typed data objects to implement the
- * ContextAwareInterface also, such that the context can be derived from the
- * parent.
- *
- * Classes deriving from this base class have to declare $value
- * or override getValue() or setValue().
- */
-abstract class ContextAwareTypedData extends TypedData implements ContextAwareInterface {
-
-  /**
-   * The property name.
-   *
-   * @var string
-   */
-  protected $name;
-
-  /**
-   * The parent typed data object.
-   *
-   * @var \Drupal\Core\TypedData\ContextAwareInterface
-   */
-  protected $parent;
-
-  /**
-   * Constructs a TypedData object given its definition and context.
-   *
-   * @param array $definition
-   *   The data definition.
-   * @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\ContextAwareInterface $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, ContextAwareInterface $parent = NULL) {
-    $this->definition = $definition;
-    $this->setContext($name, $parent);
-  }
-
-  /**
-   * Implements \Drupal\Core\TypedData\ContextAwareInterface::setContext().
-   */
-  public function setContext($name = NULL, ContextAwareInterface $parent = NULL) {
-    $this->parent = $parent;
-    $this->name = $name;
-  }
-
-  /**
-   * Implements \Drupal\Core\TypedData\ContextAwareInterface::getName().
-   */
-  public function getName() {
-    return $this->name;
-  }
-
-  /**
-   * Implements \Drupal\Core\TypedData\ContextAwareInterface::getRoot().
-   */
-  public function getRoot() {
-    if (isset($this->parent)) {
-      return $this->parent->getRoot();
-    }
-    // If no parent is set, this is the root of the data tree.
-    return $this;
-  }
-
-  /**
-   * Implements \Drupal\Core\TypedData\ContextAwareInterface::getPropertyPath().
-   */
-  public function getPropertyPath() {
-    if (isset($this->parent)) {
-      // The property path of this data object is the parent's path appended
-      // by this object's name.
-      $prefix = $this->parent->getPropertyPath();
-      return (strlen($prefix) ? $prefix . '.' : '') . $this->name;
-    }
-    // If no parent is set, this is the root of the data tree. Thus the property
-    // path equals the name of this data object.
-    elseif (isset($this->name)) {
-      return $this->name;
-    }
-    return '';
-  }
-
-  /**
-   * Implements \Drupal\Core\TypedData\ContextAwareInterface::getParent().
-   *
-   * @return \Drupal\Core\Entity\Field\FieldInterface
-   */
-  public function getParent() {
-    return $this->parent;
-  }
-}
diff --git a/core/lib/Drupal/Core/TypedData/ItemList.php b/core/lib/Drupal/Core/TypedData/ItemList.php
index 3c6d01a..88af366 100644
--- a/core/lib/Drupal/Core/TypedData/ItemList.php
+++ b/core/lib/Drupal/Core/TypedData/ItemList.php
@@ -13,7 +13,7 @@
  * This class can serve as list for any type of items.
  * Note: The class cannot be called "List" as list is a reserved PHP keyword.
  */
-class ItemList extends ContextAwareTypedData implements \IteratorAggregate, ListInterface {
+class ItemList extends TypedData implements \IteratorAggregate, ListInterface {
 
   /**
    * Numerically indexed array items.
@@ -41,7 +41,11 @@ public function getValue() {
    * @param array|null $values
    *   An array of values of the field items, or NULL to unset the field.
    */
-  public function setValue($values) {
+  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;
     }
@@ -197,15 +201,23 @@ public function isEmpty() {
   }
 
   /**
+   * Implements \Drupal\Core\TypedData\ListInterface::onChange().
+   */
+  public function onChange($delta) {
+    // Notify the parent of changes.
+    if (isset($this->parent)) {
+      $this->parent->onChange($this->name);
+    }
+  }
+
+  /**
    * Magic method: Implements a deep clone.
    */
   public function __clone() {
     if (isset($this->list)) {
       foreach ($this->list as $delta => $item) {
         $this->list[$delta] = clone $item;
-        if ($item instanceof ContextAwareInterface) {
-          $this->list[$delta]->setContext($delta, $this);
-        }
+        $this->list[$delta]->setContext($delta, $this);
       }
     }
   }
diff --git a/core/lib/Drupal/Core/TypedData/ListInterface.php b/core/lib/Drupal/Core/TypedData/ListInterface.php
index f6f906b..2711cd4 100644
--- a/core/lib/Drupal/Core/TypedData/ListInterface.php
+++ b/core/lib/Drupal/Core/TypedData/ListInterface.php
@@ -20,7 +20,7 @@
  * When implementing this interface which extends Traversable, make sure to list
  * IteratorAggregate or Iterator before this interface in the implements clause.
  */
-interface ListInterface extends ArrayAccess, Countable, Traversable {
+interface ListInterface extends TypedDataInterface, ArrayAccess, Countable, Traversable {
 
   /**
    * Determines whether the list contains any non-empty items.
@@ -37,4 +37,14 @@ public function isEmpty();
    *   The data definition of contained items.
    */
   public function getItemDefinition();
+
+  /**
+   * React to changes to a child item.
+   *
+   * Note that this is invoked before any changes are applied.
+   *
+   * @param $delta
+   *   The delta of the item which is changed.
+   */
+  public function onChange($delta);
 }
diff --git a/core/lib/Drupal/Core/TypedData/Type/Binary.php b/core/lib/Drupal/Core/TypedData/Type/Binary.php
index cf25c73..f9c4985 100644
--- a/core/lib/Drupal/Core/TypedData/Type/Binary.php
+++ b/core/lib/Drupal/Core/TypedData/Type/Binary.php
@@ -50,7 +50,11 @@ public function getValue() {
    *
    * Supports a PHP file resource or a (absolute) stream resource URI as value.
    */
-  public function setValue($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;
diff --git a/core/lib/Drupal/Core/TypedData/Type/Date.php b/core/lib/Drupal/Core/TypedData/Type/Date.php
index e326674..c9b8c6b 100644
--- a/core/lib/Drupal/Core/TypedData/Type/Date.php
+++ b/core/lib/Drupal/Core/TypedData/Type/Date.php
@@ -31,8 +31,11 @@ class Date extends TypedData {
   /**
    * Overrides TypedData::setValue().
    */
-  public function setValue($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);
+    }
     // Don't try to create a date from an empty value.
     // It would default to the current time.
     if (!isset($value)) {
diff --git a/core/lib/Drupal/Core/TypedData/Type/Duration.php b/core/lib/Drupal/Core/TypedData/Type/Duration.php
index fa539cf..52ba97d 100644
--- a/core/lib/Drupal/Core/TypedData/Type/Duration.php
+++ b/core/lib/Drupal/Core/TypedData/Type/Duration.php
@@ -31,7 +31,11 @@ class Duration extends TypedData {
   /**
    * Overrides TypedData::setValue().
    */
-  public function setValue($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);
+    }
     // Catch any exceptions thrown due to invalid values being passed.
     try {
       if ($value instanceof DateInterval || !isset($value)) {
diff --git a/core/lib/Drupal/Core/TypedData/Type/Language.php b/core/lib/Drupal/Core/TypedData/Type/Language.php
index 2226a7e..0127314 100644
--- a/core/lib/Drupal/Core/TypedData/Type/Language.php
+++ b/core/lib/Drupal/Core/TypedData/Type/Language.php
@@ -9,7 +9,7 @@
 
 use InvalidArgumentException;
 use Drupal\Core\Language\Language as LanguageObject;
-use Drupal\Core\TypedData\ContextAwareTypedData;
+use Drupal\Core\TypedData\TypedData;
 
 /**
  * Defines the 'language' data type.
@@ -25,7 +25,7 @@
  *  - langcode source: If used as computed property, the langcode property used
  *    to load the language object.
  */
-class Language extends ContextAwareTypedData {
+class Language extends TypedData {
 
   /**
    * The language code of the language if no 'langcode source' is used.
@@ -38,29 +38,21 @@ class Language extends ContextAwareTypedData {
    * Overrides TypedData::getValue().
    */
   public function getValue() {
-    $source = $this->getLanguageCodeSource();
-    $langcode = $source ? $source->getValue() : $this->langcode;
-    if ($langcode) {
-      $language = language_load($langcode);
+    if (!empty($this->definition['settings']['langcode source'])) {
+      $this->langcode = $this->parent->__get($this->definition['settings']['langcode source']);
+    }
+   if ($this->langcode) {
+      $language = language_load($this->langcode);
       return $language ?: new LanguageObject(array('langcode' => $this->langcode));
     }
   }
 
   /**
-   * Helper to get the typed data object holding the source language code.
-   *
-   * @return \Drupal\Core\TypedData\TypedDataInterface|FALSE
-   */
-  protected function getLanguageCodeSource() {
-    return !empty($this->definition['settings']['langcode source']) ? $this->parent->get($this->definition['settings']['langcode source']) : FALSE;
-  }
-
-  /**
    * Overrides TypedData::setValue().
    *
    * Both the langcode and the language object may be passed as value.
    */
-  public function setValue($value) {
+  public function setValue($value, $notify = TRUE) {
     // Support passing language objects.
     if (is_object($value)) {
       $value = $value->langcode;
@@ -68,12 +60,15 @@ public function setValue($value) {
     elseif (isset($value) && !is_scalar($value)) {
       throw new InvalidArgumentException('Value is no valid langcode or language object.');
     }
-    // Now update the value in the source or the local langcode property.
-    $source = $this->getLanguageCodeSource();
-    if ($source) {
-      $source->setValue($value);
+    // Update the 'langcode source' property, if given.
+    if (!empty($this->definition['settings']['langcode source'])) {
+      $this->parent->__set($this->definition['settings']['langcode source'], $value);
     }
     else {
+      // Notify the parent of any changes to be made.
+      if ($notify && isset($this->parent)) {
+        $this->parent->onChange($this->name);
+      }
       $this->langcode = $value;
     }
   }
diff --git a/core/lib/Drupal/Core/TypedData/Type/Map.php b/core/lib/Drupal/Core/TypedData/Type/Map.php
index 5dd3674..a05497d 100644
--- a/core/lib/Drupal/Core/TypedData/Type/Map.php
+++ b/core/lib/Drupal/Core/TypedData/Type/Map.php
@@ -7,8 +7,9 @@
 
 namespace Drupal\Core\TypedData\Type;
 
-use Drupal\Core\TypedData\ContextAwareTypedData;
+use Drupal\Core\TypedData\TypedData;
 use Drupal\Core\TypedData\ComplexDataInterface;
+use Drupal\Core\TypedData\TypedDataInterface;
 
 /**
  * The "map" data type.
@@ -20,7 +21,7 @@
  * By default there is no metadata for contained properties. Extending classes
  * may want to override Map::getPropertyDefinitions() to define it.
  */
-class Map extends ContextAwareTypedData implements \IteratorAggregate, ComplexDataInterface {
+class Map extends TypedData implements \IteratorAggregate, ComplexDataInterface {
 
   /**
    * An array of values for the contained properties.
@@ -55,7 +56,16 @@ public function getPropertyDefinitions() {
   public function getValue() {
     // Update the values and return them.
     foreach ($this->properties as $name => $property) {
-      $this->values[$name] = $property->getValue();
+      $definition = $property->getDefinition();
+      if (empty($definition['computed'])) {
+        $value = $property->getValue();
+        if (isset($value)) {
+          $this->values[$name] = $property->getValue();
+        }
+        else {
+          unset($this->values[$name]);
+        }
+      }
     }
     return $this->values;
   }
@@ -66,12 +76,24 @@ public function getValue() {
    * @param array|null $values
    *   An array of property values.
    */
-  public function setValue($values) {
+  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;
-    $this->properties = array();
+
+    // Update any existing property objects.
+    foreach ($this->properties as $name => $property) {
+      $value = NULL;
+      if (isset($values[$name])) {
+        $value = $values[$name];
+      }
+      $property->setValue($value, FALSE);
+    }
   }
 
   /**
@@ -90,11 +112,13 @@ public function getString() {
    * Implements \Drupal\Core\TypedData\ComplexDataInterface::get().
    */
   public function get($property_name) {
-    if (!$this->getPropertyDefinition($property_name)) {
-      throw new \InvalidArgumentException('Property ' . check_plain($property_name) . ' is unknown.');
-    }
     if (!isset($this->properties[$property_name])) {
-      $this->properties[$property_name] = typed_data()->getPropertyInstance($this, $property_name, isset($this->values[$property_name]) ? $this->values[$property_name] : NULL);
+      $value = NULL;
+      if (isset($this->values[$property_name])) {
+        $value = $this->values[$property_name];
+      }
+      // If the property is unknown, this will throw an exception.
+      $this->properties[$property_name] = typed_data()->getPropertyInstance($this, $property_name, $value);
     }
     return $this->properties[$property_name];
   }
@@ -103,11 +127,11 @@ public function get($property_name) {
    * Implements \Drupal\Core\TypedData\ComplexDataInterface::set().
    */
   public function set($property_name, $value) {
-    if (isset($this->properties[$property_name])) {
-      $this->properties[$property_name]->setValue($value);
+    if ($this->getPropertyDefinition($property_name)) {
+      $this->get($property_name)->setValue($value);
     }
     else {
-      // Just the plain value, so it's possible to add a new entry to the map.
+      // Just set the plain value, which allows adding a new entry to the map.
       $this->values[$property_name] = $value;
     }
   }
@@ -181,11 +205,19 @@ public function isEmpty() {
    * Magic method: Implements a deep clone.
    */
   public function __clone() {
-    foreach ($this->getProperties() as $name => $property) {
+    foreach ($this->properties as $name => $property) {
       $this->properties[$name] = clone $property;
-      if ($property instanceof ContextAwareInterface) {
-        $this->properties[$name]->setContext($name, $this);
-      }
+      $this->properties[$name]->setContext($name, $this);
+    }
+  }
+
+  /**
+   * 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/TypedData/TypedData.php b/core/lib/Drupal/Core/TypedData/TypedData.php
index d6ad4be..e9558f3 100644
--- a/core/lib/Drupal/Core/TypedData/TypedData.php
+++ b/core/lib/Drupal/Core/TypedData/TypedData.php
@@ -23,15 +23,37 @@
   protected $definition;
 
   /**
-   * Constructs a TypedData object given its definition.
+   * The property name.
+   *
+   * @var string
+   */
+  protected $name;
+
+  /**
+   * The parent typed data object.
+   *
+   * @var \Drupal\Core\TypedData\TypedDataInterface
+   */
+  protected $parent;
+
+  /**
+   * Constructs a TypedData object given its definition and context.
    *
    * @param array $definition
    *   The data definition.
+   * @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
+   *   (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) {
+  public function __construct(array $definition, $name = NULL, TypedDataInterface $parent = NULL) {
     $this->definition = $definition;
+    $this->parent = $parent;
+    $this->name = $name;
   }
 
   /**
@@ -58,7 +80,11 @@ public function getValue() {
   /**
    * Implements \Drupal\Core\TypedData\TypedDataInterface::setValue().
    */
-  public function setValue($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);
+    }
     $this->value = $value;
   }
 
@@ -84,4 +110,57 @@ public function validate() {
     // @todo: Add the typed data manager as proper dependency.
     return typed_data()->getValidator()->validate($this);
   }
+
+  /**
+   * Implements \Drupal\Core\TypedData\TypedDataInterface::setContext().
+   */
+  public function setContext($name = NULL, TypedDataInterface $parent = NULL) {
+    $this->parent = $parent;
+    $this->name = $name;
+  }
+
+  /**
+   * Implements \Drupal\Core\TypedData\TypedDataInterface::getName().
+   */
+  public function getName() {
+    return $this->name;
+  }
+
+  /**
+   * Implements \Drupal\Core\TypedData\TypedDataInterface::getRoot().
+   */
+  public function getRoot() {
+    if (isset($this->parent)) {
+      return $this->parent->getRoot();
+    }
+    // If no parent is set, this is the root of the data tree.
+    return $this;
+  }
+
+  /**
+   * Implements \Drupal\Core\TypedData\TypedDataInterface::getPropertyPath().
+   */
+  public function getPropertyPath() {
+    if (isset($this->parent)) {
+      // The property path of this data object is the parent's path appended
+      // by this object's name.
+      $prefix = $this->parent->getPropertyPath();
+      return (strlen($prefix) ? $prefix . '.' : '') . $this->name;
+    }
+    // If no parent is set, this is the root of the data tree. Thus the property
+    // path equals the name of this data object.
+    elseif (isset($this->name)) {
+      return $this->name;
+    }
+    return '';
+  }
+
+  /**
+   * Implements \Drupal\Core\TypedData\TypedDataInterface::getParent().
+   *
+   * @return \Drupal\Core\Entity\Field\FieldInterface
+   */
+  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 0fcf36f..ac2297d 100644
--- a/core/lib/Drupal/Core/TypedData/TypedDataInterface.php
+++ b/core/lib/Drupal/Core/TypedData/TypedDataInterface.php
@@ -43,11 +43,15 @@ public function getValue();
    * @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
+   *   (optional) Whether to notify the parent object of the change. Defaults to
+   *   TRUE. Usually parent objects should be notified unless the method is
+   *   invoked by the parent itself.
    *
    * @throws \Drupal\Core\TypedData\ReadOnlyException
    *   If the data is read-only.
    */
-  public function setValue($value);
+  public function setValue($value, $notify = TRUE);
 
   /**
    * Returns a string representation of the data.
@@ -73,4 +77,60 @@ public function getConstraints();
    *   succeeded.
    */
   public function validate();
+
+  /**
+   * 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 0f8dc73..195e32d 100644
--- a/core/lib/Drupal/Core/TypedData/TypedDataManager.php
+++ b/core/lib/Drupal/Core/TypedData/TypedDataManager.php
@@ -145,7 +145,7 @@ public function createInstance($plugin_id, array $configuration, $name = NULL, $
   public function create(array $definition, $value = NULL, $name = NULL, $parent = NULL) {
     $wrapper = $this->factory->createInstance($definition['type'], $definition, $name, $parent);
     if (isset($value)) {
-      $wrapper->setValue($value);
+      $wrapper->setValue($value, FALSE);
     }
     return $wrapper;
   }
@@ -156,7 +156,7 @@ public function create(array $definition, $value = NULL, $name = NULL, $parent =
    * @param array $options
    *   An array of options with the following keys:
    *   - object: The parent typed data object, implementing the
-   *     ContextAwareInterface and either the ListInterface or the
+   *     TypedDataInterface and either the ListInterface or the
    *     ComplexDataInterface.
    *   - property: The name of the property to instantiate, or the delta of the
    *     the list item to instantiate.
@@ -187,8 +187,8 @@ 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\ContextAwareInterface $object
-   *   The parent typed data object, implementing the ContextAwareInterface and
+   * @param \Drupal\Core\TypedData\TypedDataInterface $object
+   *   The parent typed data object, implementing the TypedDataInterface and
    *   either the ListInterface or the ComplexDataInterface.
    * @param string $property_name
    *   The name of the property to instantiate, or the delta of an list item.
@@ -204,8 +204,11 @@ public function getInstance(array $options) {
    *   The new property instance.
    *
    * @see \Drupal\Core\TypedData\TypedDataManager::create()
+   *
+   * @todo: Add type-hinting to $object once entities implement the
+   *   TypedDataInterface.
    */
-  public function getPropertyInstance(ContextAwareInterface $object, $property_name, $value = NULL) {
+  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
@@ -244,11 +247,9 @@ public function getPropertyInstance(ContextAwareInterface $object, $property_nam
     // Clone from the prototype, then update the parent relationship and set the
     // data value if necessary.
     $property = clone $this->prototypes[$key];
-    if ($property instanceof ContextAwareInterface) {
-      $property->setContext($property_name, $object);
-    }
+    $property->setContext($property_name, $object);
     if (isset($value)) {
-      $property->setValue($value);
+      $property->setValue($value, FALSE);
     }
     return $property;
   }
diff --git a/core/modules/comment/lib/Drupal/comment/FieldNewValue.php b/core/modules/comment/lib/Drupal/comment/FieldNewValue.php
index 52875ca..9fc5cae 100644
--- a/core/modules/comment/lib/Drupal/comment/FieldNewValue.php
+++ b/core/modules/comment/lib/Drupal/comment/FieldNewValue.php
@@ -7,7 +7,7 @@
 
 namespace Drupal\comment;
 
-use Drupal\Core\TypedData\ContextAwareTypedData;
+use Drupal\Core\TypedData\TypedData;
 use Drupal\Core\TypedData\ReadOnlyException;
 use InvalidArgumentException;
 
@@ -16,7 +16,7 @@
  *
  * @todo: Declare the list of allowed values once supported.
  */
-class FieldNewValue extends ContextAwareTypedData {
+class FieldNewValue extends TypedData {
 
   /**
    * Implements \Drupal\Core\TypedData\TypedDataInterface::getValue().
@@ -36,7 +36,7 @@ public function getValue($langcode = NULL) {
   /**
    * Implements \Drupal\Core\TypedData\TypedDataInterface::setValue().
    */
-  public function setValue($value) {
+  public function setValue($value, $notify = TRUE) {
     if (isset($value)) {
       throw new ReadOnlyException('Unable to set a computed property.');
     }
diff --git a/core/modules/file/lib/Drupal/file/Type/FileItem.php b/core/modules/file/lib/Drupal/file/Type/FileItem.php
index e1c7d24..a4dd7e5 100644
--- a/core/modules/file/lib/Drupal/file/Type/FileItem.php
+++ b/core/modules/file/lib/Drupal/file/Type/FileItem.php
@@ -8,6 +8,7 @@
 namespace Drupal\file\Type;
 
 use Drupal\Core\Entity\Field\FieldItemBase;
+use Drupal\Core\TypedData\TypedDataInterface;
 
 /**
  * Defines the 'file_field' entity field item.
@@ -24,6 +25,16 @@ class FileItem extends FieldItemBase {
   static $propertyDefinitions;
 
   /**
+   * Overrides \Drupal\Core\TypedData\TypedData::__construct().
+   */
+  public function __construct(array $definition, $name = NULL, TypedDataInterface $parent = NULL) {
+    $this->definition = $definition;
+    $this->setContext($name, $parent);
+    // Initialize the entity property by default.
+    $this->properties['entity'] = typed_data()->getPropertyInstance($this, 'entity');
+  }
+
+  /**
    * Implements \Drupal\Core\TypedData\ComplexDataInterface::getPropertyDefinitions().
    */
   public function getPropertyDefinitions() {
@@ -57,37 +68,31 @@ public function getPropertyDefinitions() {
   }
 
   /**
-   * Overrides \Drupal\Core\Entity\Field\FieldItemBase::setValue().
+   * Overrides \Drupal\Core\Entity\Field\FieldItemBase::get().
    */
-  public function setValue($values) {
-    // Treat the values as property value of the entity field, if no array
-    // is given.
+  public function setValue($values, $notify = TRUE) {
+    // Treat the values as property value of the first property, if no array is
+    // given.
     if (!is_array($values)) {
-      $values = array('entity' => $values);
+      $keys = array_keys($this->getPropertyDefinitions());
+      $values = array($keys[0] => $values);
     }
 
-    if (isset($values['display'])) {
-      $this->properties['display']->setValue($values['display']);
-    }
-    if (isset($values['description'])) {
-      $this->properties['description']->setValue($values['description']);
+    // Notify the parent of any changes to be made.
+    if ($notify && isset($this->parent)) {
+      $this->parent->onChange($this->name);
     }
+    $this->values = $values;
 
-    // Entity is computed out of the ID, so we only need to update the ID. Only
-    // set the entity field if no ID is given.
-    if (isset($values['fid'])) {
-      $this->properties['fid']->setValue($values['fid']);
-    }
-    elseif (isset($values['entity'])) {
-      $this->properties['entity']->setValue($values['entity']);
-    }
-    else {
-      $this->properties['entity']->setValue(NULL);
-    }
-    unset($values['entity'], $values['fid'], $values['display'], $values['description']);
-    if ($values) {
-      throw new \InvalidArgumentException('Property ' . key($values) . ' is unknown.');
+    // Update any existing property objects, except of 'entity'.
+    foreach ($this->properties as $name => $property) {
+      if ($name != 'entity') {
+        $value = NULL;
+        if (isset($values[$name])) {
+          $value = $values[$name];
+        }
+        $property->setValue($value, FALSE);
+      }
     }
   }
-
 }
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 880c720..f8a1147 100644
--- a/core/modules/system/lib/Drupal/system/Tests/TypedData/TypedDataTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/TypedData/TypedDataTest.php
@@ -388,7 +388,7 @@ public function testTypedDataMaps() {
 
     $properties = $typed_data->getProperties();
     $this->assertEqual(array_keys($properties), array_keys($value));
-    $this->assertIdentical($properties['one'], $typed_data->get('one'));
+    $this->assertIdentical($properties['one'], $typed_data->get('one'), 'Properties are identical.');
 
     $typed_data->setPropertyValues(array('one' => 'eins'));
     $this->assertEqual($typed_data->get('one')->getValue(), 'eins');
diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/Type/TaxonomyTermReferenceItem.php b/core/modules/taxonomy/lib/Drupal/taxonomy/Type/TaxonomyTermReferenceItem.php
index 7f7ab02..4029e90 100644
--- a/core/modules/taxonomy/lib/Drupal/taxonomy/Type/TaxonomyTermReferenceItem.php
+++ b/core/modules/taxonomy/lib/Drupal/taxonomy/Type/TaxonomyTermReferenceItem.php
@@ -8,6 +8,7 @@
 namespace Drupal\taxonomy\Type;
 
 use Drupal\Core\Entity\Field\FieldItemBase;
+use Drupal\Core\TypedData\TypedDataInterface;
 
 /**
  * Defines the 'taxonomy_term_reference' entity field item.
@@ -24,6 +25,16 @@ class TaxonomyTermReferenceItem extends FieldItemBase {
   static $propertyDefinitions;
 
   /**
+   * Overrides \Drupal\Core\TypedData\TypedData::__construct().
+   */
+  public function __construct(array $definition, $name = NULL, TypedDataInterface $parent = NULL) {
+    $this->definition = $definition;
+    $this->setContext($name, $parent);
+    // Initialize the entity property by default.
+    $this->properties['entity'] = typed_data()->getPropertyInstance($this, 'entity');
+  }
+
+  /**
    * Implements \Drupal\Core\TypedData\ComplexDataInterface::getPropertyDefinitions().
    */
   public function getPropertyDefinitions() {
@@ -49,30 +60,31 @@ public function getPropertyDefinitions() {
   }
 
   /**
-   * Overrides \Drupal\Core\Entity\Field\FieldItemBase::setValue().
+   * Overrides \Drupal\Core\Entity\Field\FieldItemBase::get().
    */
-  public function setValue($values) {
-    // Treat the values as property value of the entity field, if no array
-    // is given.
+  public function setValue($values, $notify = TRUE) {
+    // Treat the values as property value of the first property, if no array is
+    // given.
     if (!is_array($values)) {
-      $values = array('entity' => $values);
+      $keys = array_keys($this->getPropertyDefinitions());
+      $values = array($keys[0] => $values);
     }
 
-    // Entity is computed out of the ID, so we only need to update the ID. Only
-    // set the entity field if no ID is given.
-    if (isset($values['tid'])) {
-      $this->properties['tid']->setValue($values['tid']);
+    // Notify the parent of any changes to be made.
+    if ($notify && isset($this->parent)) {
+      $this->parent->onChange($this->name);
     }
-    elseif (isset($values['entity'])) {
-      $this->properties['entity']->setValue($values['entity']);
-    }
-    else {
-      $this->properties['entity']->setValue(NULL);
-    }
-    unset($values['entity'], $values['tid']);
-    if ($values) {
-      throw new \InvalidArgumentException('Property ' . key($values) . ' is unknown.');
+    $this->values = $values;
+
+    // Update any existing property objects, except of 'entity'.
+    foreach ($this->properties as $name => $property) {
+      if ($name != 'entity') {
+        $value = NULL;
+        if (isset($values[$name])) {
+          $value = $values[$name];
+        }
+        $property->setValue($value, FALSE);
+      }
     }
   }
-
 }
diff --git a/core/modules/text/lib/Drupal/text/TextProcessed.php b/core/modules/text/lib/Drupal/text/TextProcessed.php
index c73af6f..3a44722 100644
--- a/core/modules/text/lib/Drupal/text/TextProcessed.php
+++ b/core/modules/text/lib/Drupal/text/TextProcessed.php
@@ -7,8 +7,8 @@
 
 namespace Drupal\text;
 
-use Drupal\Core\TypedData\ContextAwareInterface;
-use Drupal\Core\TypedData\ContextAwareTypedData;
+use Drupal\Core\TypedData\TypedDataInterface;
+use Drupal\Core\TypedData\TypedData;
 use Drupal\Core\TypedData\ReadOnlyException;
 use InvalidArgumentException;
 
@@ -18,7 +18,7 @@
  * Required settings (below the definition's 'settings' key) are:
  *  - text source: The text property containing the to be processed text.
  */
-class TextProcessed extends ContextAwareTypedData {
+class TextProcessed extends TypedData {
 
   /**
    * The text property.
@@ -35,9 +35,9 @@ class TextProcessed extends ContextAwareTypedData {
   protected $format;
 
   /**
-   * Overrides ContextAwareTypedData::__construct().
+   * Overrides TypedData::__construct().
    */
-  public function __construct(array $definition, $name = NULL, ContextAwareInterface $parent = NULL) {
+  public function __construct(array $definition, $name = NULL, TypedDataInterface $parent = NULL) {
     parent::__construct($definition, $name, $parent);
 
     if (!isset($definition['settings']['text source'])) {
@@ -46,9 +46,9 @@ public function __construct(array $definition, $name = NULL, ContextAwareInterfa
   }
 
   /**
-   * Overrides ContextAwareTypedData::setContext().
+   * Overrides TypedData::setContext().
    */
-  public function setContext($name = NULL, ContextAwareInterface $parent = NULL) {
+  public function setContext($name = NULL, TypedDataInterface $parent = NULL) {
     parent::setContext($name, $parent);
     if (isset($parent)) {
       $this->text = $parent->get($this->definition['settings']['text source']);
@@ -81,7 +81,7 @@ public function getValue($langcode = NULL) {
   /**
    * Implements \Drupal\Core\TypedData\TypedDataInterface::setValue().
    */
-  public function setValue($value) {
+  public function setValue($value, $notify = TRUE) {
     if (isset($value)) {
       throw new ReadOnlyException('Unable to set a computed property.');
     }
diff --git a/core/modules/views/views_ui/lib/Drupal/views_ui/ViewUI.php b/core/modules/views/views_ui/lib/Drupal/views_ui/ViewUI.php
index 8c44bb0..9114a6a 100644
--- a/core/modules/views/views_ui/lib/Drupal/views_ui/ViewUI.php
+++ b/core/modules/views/views_ui/lib/Drupal/views_ui/ViewUI.php
@@ -9,7 +9,7 @@
 
 use Drupal\views\ViewExecutable;
 use Drupal\Core\Database\Database;
-use Drupal\Core\TypedData\ContextAwareInterface;
+use Drupal\Core\TypedData\TypedDataInterface;
 use Drupal\views\Plugin\views\query\Sql;
 use Drupal\views\Plugin\Core\Entity\View;
 use Drupal\views\ViewStorageInterface;
@@ -985,37 +985,93 @@ public function getOriginalEntity() {
   }
 
   /**
-   * Implements \Drupal\Core\TypedData\ContextAwareInterface::getName().
+   * Implements \Drupal\Core\TypedData\TypedDataInterface::getType().
+   */
+  public function getType() {
+    return $this->__call(__FUNCTION__, func_get_args());
+  }
+
+  /**
+   * Implements \Drupal\Core\TypedData\TypedDataInterface::getDefinition().
+   */
+  public function getDefinition() {
+    return $this->__call(__FUNCTION__, func_get_args());
+  }
+
+  /**
+   * Implements \Drupal\Core\TypedData\TypedDataInterface::getValue().
+   */
+  public function getValue() {
+    return $this->__call(__FUNCTION__, func_get_args());
+  }
+
+  /**
+   * Implements \Drupal\Core\TypedData\TypedDataInterface::setValue().
+   */
+  public function setValue($value) {
+    return $this->__call(__FUNCTION__, func_get_args());
+  }
+
+  /**
+   * Implements \Drupal\Core\TypedData\TypedDataInterface::getString().
+   */
+  public function getString() {
+    return $this->__call(__FUNCTION__, func_get_args());
+  }
+
+  /**
+   * Implements \Drupal\Core\TypedData\TypedDataInterface::getConstraints().
+   */
+  public function getConstraints() {
+    return $this->__call(__FUNCTION__, func_get_args());
+  }
+
+  /**
+   * Implements \Drupal\Core\TypedData\TypedDataInterface::validate().
+   */
+  public function validate() {
+    return $this->__call(__FUNCTION__, func_get_args());
+  }
+
+  /**
+   * Implements \Drupal\Core\TypedData\TypedDataInterface::getName().
    */
   public function getName() {
     return $this->__call(__FUNCTION__, func_get_args());
   }
 
   /**
-   * Implements \Drupal\Core\TypedData\ContextAwareInterface::getRoot().
+   * Implements \Drupal\Core\TypedData\TypedDataInterface::getRoot().
    */
   public function getRoot() {
     return $this->__call(__FUNCTION__, func_get_args());
   }
 
   /**
-   * Implements \Drupal\Core\TypedData\ContextAwareInterface::getPropertyPath().
+   * Implements \Drupal\Core\TypedData\TypedDataInterface::getPropertyPath().
    */
   public function getPropertyPath() {
     return $this->__call(__FUNCTION__, func_get_args());
   }
 
   /**
-   * Implements \Drupal\Core\TypedData\ContextAwareInterface::getParent().
+   * Implements \Drupal\Core\TypedData\TypedDataInterface::getParent().
    */
   public function getParent() {
     return $this->__call(__FUNCTION__, func_get_args());
   }
 
   /**
-   * Implements \Drupal\Core\TypedData\ContextAwareInterface::setContext().
+   * Implements \Drupal\Core\TypedData\TypedDataInterface::setContext().
+   */
+  public function setContext($name = NULL, TypedDataInterface $parent = NULL) {
+    return $this->__call(__FUNCTION__, func_get_args());
+  }
+
+  /**
+   * Implements \Drupal\Core\TypedData\TypedDataInterface::onChange().
    */
-  public function setContext($name = NULL, ContextAwareInterface $parent = NULL) {
+  public function onChange($property_name) {
     return $this->__call(__FUNCTION__, func_get_args());
   }
 }
