diff --git a/core/core.services.yml b/core/core.services.yml
index f70ace6..c6270f6 100644
--- a/core/core.services.yml
+++ b/core/core.services.yml
@@ -198,6 +198,7 @@ services:
     arguments: [slave]
   typed_data:
     class: Drupal\Core\TypedData\TypedDataManager
+    arguments: ['@container.namespaces']
     calls:
       - [setValidationConstraintManager, ['@validation.constraint']]
   validation.constraint:
diff --git a/core/includes/entity.api.php b/core/includes/entity.api.php
index 726d1b1..fd4a3bf 100644
--- a/core/includes/entity.api.php
+++ b/core/includes/entity.api.php
@@ -558,13 +558,13 @@ function hook_entity_operation_alter(array &$operations, \Drupal\Core\Entity\Ent
 /**
  * Control access to fields.
  *
- * This hook is invoked from \Drupal\Core\Entity\Field\Type\Field::access() to
+ * This hook is invoked from \Drupal\Core\Entity\Field\Field::access() to
  * let modules grant or deny operations on fields.
  *
  * @param string $operation
  *   The operation to be performed. See
  *   \Drupal\Core\TypedData\AccessibleInterface::access() for possible values.
- * @param \Drupal\Core\Entity\Field\Type\Field $field
+ * @param \Drupal\Core\Entity\Field\Field $field
  *   The entity field object on which the operation is to be performed.
  * @param \Drupal\Core\Session\AccountInterface $account
  *   The user account to check.
@@ -592,7 +592,7 @@ function hook_entity_field_access($operation, $field, \Drupal\Core\Session\Accou
  * @param array $context
  *   Context array on the performed operation with the following keys:
  *   - operation: The operation to be performed (string).
- *   - field: The entity field object (\Drupal\Core\Entity\Field\Type\Field).
+ *   - field: The entity field object (\Drupal\Core\Entity\Field\Field).
  *   - account: The user account to check access for
  *     (Drupal\user\Plugin\Core\Entity\User).
  */
diff --git a/core/lib/Drupal/Core/Entity/EntityNG.php b/core/lib/Drupal/Core/Entity/EntityNG.php
index 899ae9f..d9c6976 100644
--- a/core/lib/Drupal/Core/Entity/EntityNG.php
+++ b/core/lib/Drupal/Core/Entity/EntityNG.php
@@ -362,7 +362,7 @@ public function onChange($property_name) {
   /**
    * Implements \Drupal\Core\TypedData\TranslatableInterface::getTranslation().
    *
-   * @return \Drupal\Core\Entity\Field\Type\EntityTranslation
+   * @return \Drupal\Core\Entity\Plugin\DataType\EntityTranslation
    */
   public function getTranslation($langcode, $strict = TRUE) {
     // If the default language is Language::LANGCODE_NOT_SPECIFIED, the entity is not
diff --git a/core/lib/Drupal/Core/Entity/Field/Field.php b/core/lib/Drupal/Core/Entity/Field/Field.php
new file mode 100644
index 0000000..3948ddf
--- /dev/null
+++ b/core/lib/Drupal/Core/Entity/Field/Field.php
@@ -0,0 +1,296 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Entity\Field\Field.
+ */
+
+namespace Drupal\Core\Entity\Field;
+
+use Drupal\Core\Entity\Field\FieldInterface;
+use Drupal\Core\Session\AccountInterface;
+use Drupal\Core\TypedData\TypedDataInterface;
+use Drupal\Core\TypedData\ItemList;
+
+/**
+ * Represents an entity field; that is, a list of field item objects.
+ *
+ * An entity field is a list of field items, which contain only primitive
+ * properties or entity references. Note that even single-valued entity
+ * fields are represented as list of items, however for easy access to the
+ * contained item the entity field delegates __get() and __set() calls
+ * directly to the first item.
+ *
+ * Supported settings (below the definition's 'settings' key) are:
+ * - default_value: (optional) If set, the default value to apply to the field.
+ *
+ * @see \Drupal\Core\Entity\Field\FieldInterface
+ */
+class Field extends ItemList implements FieldInterface {
+
+  /**
+   * Numerically indexed array of field items, implementing the
+   * FieldItemInterface.
+   *
+   * @var array
+   */
+  protected $list = array();
+
+  /**
+   * Overrides TypedData::__construct().
+   */
+  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
+    // \Drupal\Core\TypedData\TypedDataManager::getPropertyInstance() will
+    // already have this field item ready for use after cloning.
+    $this->list[0] = $this->createItem(0);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function filterEmptyValues() {
+    if (isset($this->list)) {
+      $this->list = array_values(array_filter($this->list, function($item) {
+        return !$item->isEmpty();
+      }));
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   * @todo Revisit the need when all entity types are converted to NG entities.
+   */
+  public function getValue($include_computed = FALSE) {
+    if (isset($this->list)) {
+      $values = array();
+      foreach ($this->list as $delta => $item) {
+        $values[$delta] = $item->getValue($include_computed);
+      }
+      return $values;
+    }
+  }
+
+  /**
+   * 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;
+    }
+    else {
+      // Support passing in only the value of the first item.
+      if (!is_array($values) || !is_numeric(current(array_keys($values)))) {
+        $values = array(0 => $values);
+      }
+
+      // Clear the values of properties for which no value has been passed.
+      if (isset($this->list)) {
+        $this->list = array_intersect_key($this->list, $values);
+      }
+
+      // Set the values.
+      foreach ($values as $delta => $value) {
+        if (!is_numeric($delta)) {
+          throw new \InvalidArgumentException('Unable to set a value with a non-numeric delta in a list.');
+        }
+        elseif (!isset($this->list[$delta])) {
+          $this->list[$delta] = $this->createItem($delta, $value);
+        }
+        else {
+          $this->list[$delta]->setValue($value, FALSE);
+        }
+      }
+    }
+  }
+
+  /**
+   * Implements \Drupal\Core\Entity\Field\FieldInterface::getPropertyDefinition().
+   */
+  public function getPropertyDefinition($name) {
+    return $this->offsetGet(0)->getPropertyDefinition($name);
+  }
+
+  /**
+   * Implements \Drupal\Core\Entity\Field\FieldInterface::getPropertyDefinitions().
+   */
+  public function getPropertyDefinitions() {
+    return $this->offsetGet(0)->getPropertyDefinitions();
+  }
+
+  /**
+   * Implements \Drupal\Core\Entity\Field\FieldInterface::__get().
+   */
+  public function __get($property_name) {
+    return $this->offsetGet(0)->__get($property_name);
+  }
+
+  /**
+   * Implements \Drupal\Core\Entity\Field\FieldInterface::get().
+   */
+  public function get($property_name) {
+    return $this->offsetGet(0)->get($property_name);
+  }
+
+  /**
+   * Implements \Drupal\Core\Entity\Field\FieldInterface::__set().
+   */
+  public function __set($property_name, $value) {
+    $this->offsetGet(0)->__set($property_name, $value);
+  }
+
+  /**
+   * Implements \Drupal\Core\Entity\Field\FieldInterface::__isset().
+   */
+  public function __isset($property_name) {
+    return $this->offsetGet(0)->__isset($property_name);
+  }
+
+  /**
+   * Implements \Drupal\Core\Entity\Field\FieldInterface::__unset().
+   */
+  public function __unset($property_name) {
+    return $this->offsetGet(0)->__unset($property_name);
+  }
+
+  /**
+   * Implements \Drupal\Core\TypedData\AccessibleInterface::access().
+   */
+  public function access($operation = 'view', AccountInterface $account = NULL) {
+    global $user;
+    if (!isset($account) && $user->uid) {
+      $account = user_load($user->uid);
+    }
+    // Get the default access restriction that lives within this field.
+    $access = $this->defaultAccess($operation, $account);
+    // Invoke hook and collect grants/denies for field access from other
+    // modules. Our default access flag is masked under the ':default' key.
+    $grants = array(':default' => $access);
+    $hook_implementations = \Drupal::moduleHandler()->getImplementations('entity_field_access');
+    foreach ($hook_implementations as $module) {
+      $grants = array_merge($grants, array($module => module_invoke($module, 'entity_field_access', $operation, $this, $account)));
+    }
+    // Also allow modules to alter the returned grants/denies.
+    $context = array(
+      'operation' => $operation,
+      'field' => $this,
+      'account' => $account,
+    );
+    drupal_alter('entity_field_access', $grants, $context);
+
+    // One grant being FALSE is enough to deny access immediately.
+    if (in_array(FALSE, $grants, TRUE)) {
+      return FALSE;
+    }
+    // At least one grant has the explicit opinion to allow access.
+    if (in_array(TRUE, $grants, TRUE)) {
+      return TRUE;
+    }
+    // All grants are NULL and have no opinion - deny access in that case.
+    return FALSE;
+  }
+
+  /**
+   * Contains the default access logic of this field.
+   *
+   * See \Drupal\Core\TypedData\AccessibleInterface::access() for the parameter
+   * doucmentation. This method can be overriden by field sub classes to provide
+   * a different default access logic. That allows them to inherit the complete
+   * access() method which contains the access hook invocation logic.
+   *
+   * @return bool
+   *   TRUE if access to this field is allowed per default, FALSE otherwise.
+   */
+  public function defaultAccess($operation = 'view', AccountInterface $account = NULL) {
+    // Grant access per default.
+    return TRUE;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function applyDefaultValue($notify = TRUE) {
+    if (isset($this->definition['settings']['default_value'])) {
+      $this->setValue($this->definition['settings']['default_value'], $notify);
+    }
+    else {
+      // Create one field item and apply defaults.
+      $this->offsetGet(0)->applyDefaultValue(FALSE);
+    }
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getConstraints() {
+    // Constraints usually apply to the field item, but required does make
+    // sense on the field only. So we special-case it to apply to the field for
+    // now.
+    // @todo: Separate list and list item definitions to separate constraints.
+    $constraints = array();
+    if (!empty($this->definition['required'])) {
+      $constraints[] = \Drupal::typedData()->getValidationConstraintManager()->create('NotNull', array());
+    }
+    return $constraints;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function preSave() {
+    // Filter out empty items.
+    $this->filterEmptyValues();
+
+    $this->delegateMethod('presave');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function insert() {
+    $this->delegateMethod('insert');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function update() {
+    $this->delegateMethod('update');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function delete() {
+    $this->delegateMethod('delete');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function deleteRevision() {
+    $this->delegateMethod('deleteRevision');
+  }
+
+  /**
+   * Calls a method on each FieldItem.
+   *
+   * @param string $method
+   *   The name of the method.
+   */
+  protected function delegateMethod($method) {
+    if (isset($this->list)) {
+      foreach ($this->list as $item) {
+        $item->{$method}();
+      }
+    }
+  }
+
+}
diff --git a/core/lib/Drupal/Core/Entity/Field/FieldItemBase.php b/core/lib/Drupal/Core/Entity/Field/FieldItemBase.php
index d21c8cc..07704ca 100644
--- a/core/lib/Drupal/Core/Entity/Field/FieldItemBase.php
+++ b/core/lib/Drupal/Core/Entity/Field/FieldItemBase.php
@@ -8,7 +8,7 @@
 namespace Drupal\Core\Entity\Field;
 
 use Drupal\Core\Entity\EntityInterface;
-use Drupal\Core\TypedData\Type\Map;
+use Drupal\Core\TypedData\Plugin\DataType\Map;
 use Drupal\Core\TypedData\TypedDataInterface;
 use Drupal\user;
 
@@ -80,7 +80,7 @@ public function __get($name) {
   }
 
   /**
-   * Overrides \Drupal\Core\TypedData\Type\Map::set().
+   * {@inheritdoc}
    */
   public function set($property_name, $value, $notify = TRUE) {
     // Notify the parent of any changes to be made.
diff --git a/core/lib/Drupal/Core/Entity/Field/Type/BooleanItem.php b/core/lib/Drupal/Core/Entity/Field/Type/BooleanItem.php
deleted file mode 100644
index f73b013..0000000
--- a/core/lib/Drupal/Core/Entity/Field/Type/BooleanItem.php
+++ /dev/null
@@ -1,39 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\Core\Entity\Field\Type\BooleanItem.
- */
-
-namespace Drupal\Core\Entity\Field\Type;
-
-use Drupal\Core\Entity\Field\FieldItemBase;
-
-/**
- * Defines the 'boolean_field' entity field item.
- */
-class BooleanItem extends FieldItemBase {
-
-  /**
-   * Definitions of the contained properties.
-   *
-   * @see BooleanItem::getPropertyDefinitions()
-   *
-   * @var array
-   */
-  static $propertyDefinitions;
-
-  /**
-   * Implements \Drupal\Core\TypedData\ComplexDataInterface::getPropertyDefinitions().
-   */
-  public function getPropertyDefinitions() {
-
-    if (!isset(static::$propertyDefinitions)) {
-      static::$propertyDefinitions['value'] = array(
-        'type' => 'boolean',
-        'label' => t('Boolean value'),
-      );
-    }
-    return static::$propertyDefinitions;
-  }
-}
diff --git a/core/lib/Drupal/Core/Entity/Field/Type/DateItem.php b/core/lib/Drupal/Core/Entity/Field/Type/DateItem.php
deleted file mode 100644
index 33b4ec4..0000000
--- a/core/lib/Drupal/Core/Entity/Field/Type/DateItem.php
+++ /dev/null
@@ -1,39 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\Core\Entity\Field\Type\DateItem.
- */
-
-namespace Drupal\Core\Entity\Field\Type;
-
-use Drupal\Core\Entity\Field\FieldItemBase;
-
-/**
- * Defines the 'date_field' entity field item.
- */
-class DateItem extends FieldItemBase {
-
-  /**
-   * Definitions of the contained properties.
-   *
-   * @see DateItem::getPropertyDefinitions()
-   *
-   * @var array
-   */
-  static $propertyDefinitions;
-
-  /**
-   * Implements \Drupal\Core\TypedData\ComplexDataInterface::getPropertyDefinitions().
-   */
-  public function getPropertyDefinitions() {
-
-    if (!isset(static::$propertyDefinitions)) {
-      static::$propertyDefinitions['value'] = array(
-        'type' => 'date',
-        'label' => t('Date value'),
-      );
-    }
-    return static::$propertyDefinitions;
-  }
-}
diff --git a/core/lib/Drupal/Core/Entity/Field/Type/EmailItem.php b/core/lib/Drupal/Core/Entity/Field/Type/EmailItem.php
deleted file mode 100644
index 6d878ed..0000000
--- a/core/lib/Drupal/Core/Entity/Field/Type/EmailItem.php
+++ /dev/null
@@ -1,46 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\Core\Entity\Field\Type\EmailItem.
- */
-
-namespace Drupal\Core\Entity\Field\Type;
-
-use Drupal\field\Plugin\field\field_type\LegacyConfigFieldItem;
-
-/**
- * Defines the 'email_field' entity field item.
- */
-class EmailItem extends LegacyConfigFieldItem {
-
-  /**
-   * Definitions of the contained properties.
-   *
-   * @see EmailItem::getPropertyDefinitions()
-   *
-   * @var array
-   */
-  static $propertyDefinitions;
-
-  /**
-   * Implements ComplexDataInterface::getPropertyDefinitions().
-   */
-  public function getPropertyDefinitions() {
-
-    if (!isset(static::$propertyDefinitions)) {
-      static::$propertyDefinitions['value'] = array(
-        'type' => 'email',
-        'label' => t('E-mail value'),
-      );
-    }
-    return static::$propertyDefinitions;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function isEmpty() {
-    return !isset($this->values['value']) || $this->values['value'] === '';
-  }
-}
diff --git a/core/lib/Drupal/Core/Entity/Field/Type/EntityReferenceItem.php b/core/lib/Drupal/Core/Entity/Field/Type/EntityReferenceItem.php
deleted file mode 100644
index f568aec..0000000
--- a/core/lib/Drupal/Core/Entity/Field/Type/EntityReferenceItem.php
+++ /dev/null
@@ -1,105 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\Core\Entity\Field\Type\EntityReferenceItem.
- */
-
-namespace Drupal\Core\Entity\Field\Type;
-
-use Drupal\Core\Entity\Field\FieldItemBase;
-use Drupal\Core\TypedData\TypedDataInterface;
-
-/**
- * Defines the 'entity_reference' entity field item.
- *
- * Required settings (below the definition's 'settings' key) are:
- *  - target_type: The entity type to reference.
- */
-class EntityReferenceItem extends FieldItemBase {
-
-  /**
-   * Definitions of the contained properties.
-   *
-   * @see EntityReferenceItem::getPropertyDefinitions()
-   *
-   * @var array
-   */
-  static $propertyDefinitions;
-
-  /**
-   * 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'];
-
-    if (!isset(self::$propertyDefinitions[$target_type])) {
-      static::$propertyDefinitions[$target_type]['target_id'] = array(
-        // @todo: Lookup the entity type's ID data type and use it here.
-        'type' => 'integer',
-        'label' => t('Entity ID'),
-        'constraints' => array(
-          'Range' => array('min' => 0),
-        ),
-      );
-      static::$propertyDefinitions[$target_type]['entity'] = array(
-        'type' => 'entity',
-        'constraints' => array(
-          'EntityType' => $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'),
-      );
-    }
-    return static::$propertyDefinitions[$target_type];
-  }
-
-  /**
-   * Overrides \Drupal\Core\Entity\Field\FieldItemBase::__get().
-   */
-  public function __get($name) {
-    $name = ($name == 'value') ? 'target_id' : $name;
-    return parent::__get($name);
-  }
-
-  /**
-   * Overrides \Drupal\Core\Entity\Field\FieldItemBase::get().
-   */
-  public function get($property_name) {
-    $property_name = ($property_name == 'value') ? 'target_id' : $property_name;
-    return parent::get($property_name);
-  }
-
-  /**
-   * Implements \Drupal\Core\Entity\Field\FieldItemInterface::__isset().
-   */
-  public function __isset($property_name) {
-    $property_name = ($property_name == 'value') ? 'target_id' : $property_name;
-    return parent::__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.
-      $this->properties['entity']->setValue($values, $notify);
-    }
-    else {
-      // Make sure that the 'entity' property gets set as 'target_id'.
-      if (isset($values['target_id']) && !isset($values['entity'])) {
-        $values['entity'] = $values['target_id'];
-      }
-      parent::setValue($values, $notify);
-    }
-  }
-}
diff --git a/core/lib/Drupal/Core/Entity/Field/Type/EntityTranslation.php b/core/lib/Drupal/Core/Entity/Field/Type/EntityTranslation.php
deleted file mode 100644
index 859fa9a..0000000
--- a/core/lib/Drupal/Core/Entity/Field/Type/EntityTranslation.php
+++ /dev/null
@@ -1,224 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\Core\Entity\Type\EntityTranslation.
- */
-
-namespace Drupal\Core\Entity\Field\Type;
-
-use Drupal\Core\Session\AccountInterface;
-use Drupal\Core\TypedData\AccessibleInterface;
-use Drupal\Core\TypedData\ComplexDataInterface;
-use Drupal\Core\TypedData\TypedData;
-use ArrayIterator;
-use Drupal\Core\TypedData\TypedDataInterface;
-use IteratorAggregate;
-use InvalidArgumentException;
-
-/**
- * Allows accessing and updating translated entity fields.
- *
- * 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 TypedData implements IteratorAggregate, AccessibleInterface, ComplexDataInterface {
-
-  /**
-   * The array of translated fields, each being an instance of
-   * \Drupal\Core\Entity\FieldInterface.
-   *
-   * @var array
-   */
-  protected $fields = array();
-
-  /**
-   * Whether the entity translation acts in strict mode.
-   *
-   * @var boolean
-   */
-  protected $strict = TRUE;
-
-  /**
-   * Returns whether the entity translation acts in strict mode.
-   *
-   * @return boolean
-   *   Whether the entity translation acts in strict mode.
-   */
-  public function getStrictMode() {
-    return $this->strict;
-  }
-
-  /**
-   * Sets whether the entity translation acts in strict mode.
-   *
-   * @param boolean $strict
-   *   Whether the entity translation acts in strict mode.
-   *
-   * @see \Drupal\Core\TypedData\TranslatableInterface::getTranslation()
-   */
-  public function setStrictMode($strict = TRUE) {
-    $this->strict = $strict;
-  }
-
-  /**
-   * Overrides \Drupal\Core\TypedData\TypedData::getValue().
-   */
-  public function getValue() {
-    // The plain value of the translation is the array of translated field
-    // objects.
-    return $this->fields;
-  }
-
-  /**
-   * Overrides \Drupal\Core\TypedData\TypedData::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);
-    }
-    $this->fields = $values;
-  }
-
-  /**
-   * Overrides \Drupal\Core\TypedData\TypedData::getString().
-   */
-  public function getString() {
-    $strings = array();
-    foreach ($this->getProperties() as $property) {
-      $strings[] = $property->getString();
-    }
-    return implode(', ', array_filter($strings));
-  }
-
-  /**
-   * Implements \Drupal\Core\TypedData\ComplexDataInterface::get().
-   */
-  public function get($property_name) {
-    $definitions = $this->getPropertyDefinitions();
-    if (!isset($definitions[$property_name])) {
-      throw new InvalidArgumentException(format_string('Field @name is unknown or not translatable.', array('@name' => $property_name)));
-    }
-    return $this->fields[$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) {
-    $properties = array();
-    foreach ($this->getPropertyDefinitions() as $name => $definition) {
-      if ($include_computed || empty($definition['computed'])) {
-        $properties[$name] = $this->get($name);
-      }
-    }
-    return $properties;
-  }
-
-  /**
-   * Magic method: Gets a translated field.
-   */
-  public function __get($name) {
-    return $this->get($name);
-  }
-
-  /**
-   * Magic method: Sets a translated field.
-   */
-  public function __set($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::getPropertyDefinitions().
-   */
-  public function getPropertyDefinitions() {
-    $definitions = array();
-    foreach ($this->parent->getPropertyDefinitions() as $name => $definition) {
-      if (!empty($definition['translatable']) || !$this->strict) {
-        $definitions[$name] = $definition;
-      }
-    }
-    return $definitions;
-  }
-
-  /**
-   * 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 \Drupal\Core\TypedData\ComplexDataInterface::isEmpty().
-   */
-  public function isEmpty() {
-    foreach ($this->getProperties() as $property) {
-      if ($property->getValue() !== NULL) {
-        return FALSE;
-      }
-    }
-    return TRUE;
-  }
-
-  /**
-   * 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', AccountInterface $account = NULL) {
-    // Determine the language code of this translation by cutting of the
-    // leading "@" from the property name to get the langcode.
-    // @todo Add a way to set and get the langcode so that's more obvious what
-    // we're doing here.
-    $langcode = substr($this->getName(), 1);
-    return \Drupal::entityManager()
-      ->getAccessController($this->parent->entityType())
-      ->access($this->parent, $operation, $langcode, $account);
-  }
-}
diff --git a/core/lib/Drupal/Core/Entity/Field/Type/EntityWrapper.php b/core/lib/Drupal/Core/Entity/Field/Type/EntityWrapper.php
deleted file mode 100644
index 2b2b54a..0000000
--- a/core/lib/Drupal/Core/Entity/Field/Type/EntityWrapper.php
+++ /dev/null
@@ -1,219 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\Core\Entity\Field\Type\EntityWrapper.
- */
-
-namespace Drupal\Core\Entity\Field\Type;
-
-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.
- */
-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/Field/Type/Field.php b/core/lib/Drupal/Core/Entity/Field/Type/Field.php
deleted file mode 100644
index 4d53c18..0000000
--- a/core/lib/Drupal/Core/Entity/Field/Type/Field.php
+++ /dev/null
@@ -1,296 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\Core\Entity\Field\Type\Field.
- */
-
-namespace Drupal\Core\Entity\Field\Type;
-
-use Drupal\Core\Entity\Field\FieldInterface;
-use Drupal\Core\Session\AccountInterface;
-use Drupal\Core\TypedData\TypedDataInterface;
-use Drupal\Core\TypedData\ItemList;
-
-/**
- * Represents an entity field; that is, a list of field item objects.
- *
- * An entity field is a list of field items, which contain only primitive
- * properties or entity references. Note that even single-valued entity
- * fields are represented as list of items, however for easy access to the
- * contained item the entity field delegates __get() and __set() calls
- * directly to the first item.
- *
- * Supported settings (below the definition's 'settings' key) are:
- * - default_value: (optional) If set, the default value to apply to the field.
- *
- * @see \Drupal\Core\Entity\Field\FieldInterface
- */
-class Field extends ItemList implements FieldInterface {
-
-  /**
-   * Numerically indexed array of field items, implementing the
-   * FieldItemInterface.
-   *
-   * @var array
-   */
-  protected $list = array();
-
-  /**
-   * Overrides TypedData::__construct().
-   */
-  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
-    // \Drupal\Core\TypedData\TypedDataManager::getPropertyInstance() will
-    // already have this field item ready for use after cloning.
-    $this->list[0] = $this->createItem(0);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function filterEmptyValues() {
-    if (isset($this->list)) {
-      $this->list = array_values(array_filter($this->list, function($item) {
-        return !$item->isEmpty();
-      }));
-    }
-  }
-
-  /**
-   * {@inheritdoc}
-   * @todo Revisit the need when all entity types are converted to NG entities.
-   */
-  public function getValue($include_computed = FALSE) {
-    if (isset($this->list)) {
-      $values = array();
-      foreach ($this->list as $delta => $item) {
-        $values[$delta] = $item->getValue($include_computed);
-      }
-      return $values;
-    }
-  }
-
-  /**
-   * 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;
-    }
-    else {
-      // Support passing in only the value of the first item.
-      if (!is_array($values) || !is_numeric(current(array_keys($values)))) {
-        $values = array(0 => $values);
-      }
-
-      // Clear the values of properties for which no value has been passed.
-      if (isset($this->list)) {
-        $this->list = array_intersect_key($this->list, $values);
-      }
-
-      // Set the values.
-      foreach ($values as $delta => $value) {
-        if (!is_numeric($delta)) {
-          throw new \InvalidArgumentException('Unable to set a value with a non-numeric delta in a list.');
-        }
-        elseif (!isset($this->list[$delta])) {
-          $this->list[$delta] = $this->createItem($delta, $value);
-        }
-        else {
-          $this->list[$delta]->setValue($value, FALSE);
-        }
-      }
-    }
-  }
-
-  /**
-   * Implements \Drupal\Core\Entity\Field\FieldInterface::getPropertyDefinition().
-   */
-  public function getPropertyDefinition($name) {
-    return $this->offsetGet(0)->getPropertyDefinition($name);
-  }
-
-  /**
-   * Implements \Drupal\Core\Entity\Field\FieldInterface::getPropertyDefinitions().
-   */
-  public function getPropertyDefinitions() {
-    return $this->offsetGet(0)->getPropertyDefinitions();
-  }
-
-  /**
-   * Implements \Drupal\Core\Entity\Field\FieldInterface::__get().
-   */
-  public function __get($property_name) {
-    return $this->offsetGet(0)->__get($property_name);
-  }
-
-  /**
-   * Implements \Drupal\Core\Entity\Field\FieldInterface::get().
-   */
-  public function get($property_name) {
-    return $this->offsetGet(0)->get($property_name);
-  }
-
-  /**
-   * Implements \Drupal\Core\Entity\Field\FieldInterface::__set().
-   */
-  public function __set($property_name, $value) {
-    $this->offsetGet(0)->__set($property_name, $value);
-  }
-
-  /**
-   * Implements \Drupal\Core\Entity\Field\FieldInterface::__isset().
-   */
-  public function __isset($property_name) {
-    return $this->offsetGet(0)->__isset($property_name);
-  }
-
-  /**
-   * Implements \Drupal\Core\Entity\Field\FieldInterface::__unset().
-   */
-  public function __unset($property_name) {
-    return $this->offsetGet(0)->__unset($property_name);
-  }
-
-  /**
-   * Implements \Drupal\Core\TypedData\AccessibleInterface::access().
-   */
-  public function access($operation = 'view', AccountInterface $account = NULL) {
-    global $user;
-    if (!isset($account) && $user->uid) {
-      $account = user_load($user->uid);
-    }
-    // Get the default access restriction that lives within this field.
-    $access = $this->defaultAccess($operation, $account);
-    // Invoke hook and collect grants/denies for field access from other
-    // modules. Our default access flag is masked under the ':default' key.
-    $grants = array(':default' => $access);
-    $hook_implementations = \Drupal::moduleHandler()->getImplementations('entity_field_access');
-    foreach ($hook_implementations as $module) {
-      $grants = array_merge($grants, array($module => module_invoke($module, 'entity_field_access', $operation, $this, $account)));
-    }
-    // Also allow modules to alter the returned grants/denies.
-    $context = array(
-      'operation' => $operation,
-      'field' => $this,
-      'account' => $account,
-    );
-    drupal_alter('entity_field_access', $grants, $context);
-
-    // One grant being FALSE is enough to deny access immediately.
-    if (in_array(FALSE, $grants, TRUE)) {
-      return FALSE;
-    }
-    // At least one grant has the explicit opinion to allow access.
-    if (in_array(TRUE, $grants, TRUE)) {
-      return TRUE;
-    }
-    // All grants are NULL and have no opinion - deny access in that case.
-    return FALSE;
-  }
-
-  /**
-   * Contains the default access logic of this field.
-   *
-   * See \Drupal\Core\TypedData\AccessibleInterface::access() for the parameter
-   * doucmentation. This method can be overriden by field sub classes to provide
-   * a different default access logic. That allows them to inherit the complete
-   * access() method which contains the access hook invocation logic.
-   *
-   * @return bool
-   *   TRUE if access to this field is allowed per default, FALSE otherwise.
-   */
-  public function defaultAccess($operation = 'view', AccountInterface $account = NULL) {
-    // Grant access per default.
-    return TRUE;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function applyDefaultValue($notify = TRUE) {
-    if (isset($this->definition['settings']['default_value'])) {
-      $this->setValue($this->definition['settings']['default_value'], $notify);
-    }
-    else {
-      // Create one field item and apply defaults.
-      $this->offsetGet(0)->applyDefaultValue(FALSE);
-    }
-    return $this;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getConstraints() {
-    // Constraints usually apply to the field item, but required does make
-    // sense on the field only. So we special-case it to apply to the field for
-    // now.
-    // @todo: Separate list and list item definitions to separate constraints.
-    $constraints = array();
-    if (!empty($this->definition['required'])) {
-      $constraints[] = \Drupal::typedData()->getValidationConstraintManager()->create('NotNull', array());
-    }
-    return $constraints;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function preSave() {
-    // Filter out empty items.
-    $this->filterEmptyValues();
-
-    $this->delegateMethod('presave');
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function insert() {
-    $this->delegateMethod('insert');
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function update() {
-    $this->delegateMethod('update');
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function delete() {
-    $this->delegateMethod('delete');
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function deleteRevision() {
-    $this->delegateMethod('deleteRevision');
-  }
-
-  /**
-   * Calls a method on each FieldItem.
-   *
-   * @param string $method
-   *   The name of the method.
-   */
-  protected function delegateMethod($method) {
-    if (isset($this->list)) {
-      foreach ($this->list as $item) {
-        $item->{$method}();
-      }
-    }
-  }
-
-}
diff --git a/core/lib/Drupal/Core/Entity/Field/Type/IntegerItem.php b/core/lib/Drupal/Core/Entity/Field/Type/IntegerItem.php
deleted file mode 100644
index b58529e..0000000
--- a/core/lib/Drupal/Core/Entity/Field/Type/IntegerItem.php
+++ /dev/null
@@ -1,39 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\Core\Entity\Field\Type\IntegerItem.
- */
-
-namespace Drupal\Core\Entity\Field\Type;
-
-use Drupal\Core\Entity\Field\FieldItemBase;
-
-/**
- * Defines the 'integer_field' entity field item.
- */
-class IntegerItem extends FieldItemBase {
-
-  /**
-   * Definitions of the contained properties.
-   *
-   * @see IntegerItem::getPropertyDefinitions()
-   *
-   * @var array
-   */
-  static $propertyDefinitions;
-
-  /**
-   * Implements \Drupal\Core\TypedData\ComplexDataInterface::getPropertyDefinitions().
-   */
-  public function getPropertyDefinitions() {
-
-    if (!isset(static::$propertyDefinitions)) {
-      static::$propertyDefinitions['value'] = array(
-        'type' => 'integer',
-        'label' => t('Integer value'),
-      );
-    }
-    return static::$propertyDefinitions;
-  }
-}
diff --git a/core/lib/Drupal/Core/Entity/Field/Type/LanguageItem.php b/core/lib/Drupal/Core/Entity/Field/Type/LanguageItem.php
deleted file mode 100644
index 3aa2bb3..0000000
--- a/core/lib/Drupal/Core/Entity/Field/Type/LanguageItem.php
+++ /dev/null
@@ -1,78 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\Core\Entity\Field\Type\LanguageItem.
- */
-
-namespace Drupal\Core\Entity\Field\Type;
-
-use Drupal\Core\Entity\Field\FieldItemBase;
-use Drupal\Core\Language\Language;
-
-/**
- * Defines the 'language_field' entity field item.
- */
-class LanguageItem extends FieldItemBase {
-
-  /**
-   * Definitions of the contained properties.
-   *
-   * @see LanguageItem::getPropertyDefinitions()
-   *
-   * @var array
-   */
-  static $propertyDefinitions;
-
-  /**
-   * 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',
-        'label' => t('Language object'),
-        // The language object is retrieved via the language code.
-        'computed' => TRUE,
-        'read-only' => FALSE,
-        'settings' => array('langcode source' => 'value'),
-      );
-    }
-    return static::$propertyDefinitions;
-  }
-
-  /**
-   * Overrides \Drupal\Core\Entity\Field\FieldItemBase::get().
-   */
-  public function setValue($values, $notify = TRUE) {
-    // Treat the values as property value of the language property, if no array
-    // is given as this handles language codes and objects.
-    if (isset($values) && !is_array($values)) {
-      // Directly update the property instead of invoking the parent, so that
-      // the language property can take care of updating the language code
-      // property.
-      $this->properties['language']->setValue($values, $notify);
-    }
-    else {
-      // Make sure that the 'language' property gets set as 'value'.
-      if (isset($values['value']) && !isset($values['language'])) {
-        $values['language'] = $values['value'];
-      }
-      parent::setValue($values, $notify);
-    }
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function applyDefaultValue($notify = TRUE) {
-    // Default to LANGCODE_NOT_SPECIFIED.
-    $this->setValue(array('value' => Language::LANGCODE_NOT_SPECIFIED), $notify);
-    return $this;
-  }
-}
diff --git a/core/lib/Drupal/Core/Entity/Field/Type/StringItem.php b/core/lib/Drupal/Core/Entity/Field/Type/StringItem.php
deleted file mode 100644
index 7a6fdc0..0000000
--- a/core/lib/Drupal/Core/Entity/Field/Type/StringItem.php
+++ /dev/null
@@ -1,39 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\Core\Entity\Field\Type\StringItem.
- */
-
-namespace Drupal\Core\Entity\Field\Type;
-
-use Drupal\Core\Entity\Field\FieldItemBase;
-
-/**
- * Defines the 'string_field' entity field item.
- */
-class StringItem extends FieldItemBase {
-
-  /**
-   * Definitions of the contained properties.
-   *
-   * @see StringItem::getPropertyDefinitions()
-   *
-   * @var array
-   */
-  static $propertyDefinitions;
-
-  /**
-   * Implements \Drupal\Core\TypedData\ComplexDataInterface::getPropertyDefinitions().
-   */
-  public function getPropertyDefinitions() {
-
-    if (!isset(static::$propertyDefinitions)) {
-      static::$propertyDefinitions['value'] = array(
-        'type' => 'string',
-        'label' => t('Text value'),
-      );
-    }
-    return static::$propertyDefinitions;
-  }
-}
diff --git a/core/lib/Drupal/Core/Entity/Field/Type/UriItem.php b/core/lib/Drupal/Core/Entity/Field/Type/UriItem.php
deleted file mode 100644
index e5b84d4..0000000
--- a/core/lib/Drupal/Core/Entity/Field/Type/UriItem.php
+++ /dev/null
@@ -1,39 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\Core\Entity\Field\Type\UriItem.
- */
-
-namespace Drupal\Core\Entity\Field\Type;
-
-use Drupal\Core\Entity\Field\FieldItemBase;
-
-/**
- * Defines the 'uri_field' entity field item.
- */
-class UriItem extends FieldItemBase {
-
-  /**
-   * Field definitions of the contained properties.
-   *
-   * @see self::getPropertyDefinitions()
-   *
-   * @var array
-   */
-  static $propertyDefinitions;
-
-  /**
-   * Implements ComplexDataInterface::getPropertyDefinitions().
-   */
-  public function getPropertyDefinitions() {
-
-    if (!isset(self::$propertyDefinitions)) {
-      self::$propertyDefinitions['value'] = array(
-        'type' => 'string',
-        'label' => t('Text value'),
-      );
-    }
-    return self::$propertyDefinitions;
-  }
-}
diff --git a/core/lib/Drupal/Core/Entity/Field/Type/UuidItem.php b/core/lib/Drupal/Core/Entity/Field/Type/UuidItem.php
deleted file mode 100644
index 855d942..0000000
--- a/core/lib/Drupal/Core/Entity/Field/Type/UuidItem.php
+++ /dev/null
@@ -1,28 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\Core\Entity\Field\Type\UuidItem.
- */
-
-namespace Drupal\Core\Entity\Field\Type;
-
-use Drupal\Component\Uuid\Uuid;
-
-/**
- * Defines the 'uuid_field' entity field item.
- *
- * The field uses a newly generated UUID as default value.
- */
-class UuidItem extends StringItem {
-
-  /**
-   * {@inheritdoc}
-   */
-  public function applyDefaultValue($notify = TRUE) {
-    // Default to one field item with a generated UUID.
-    $uuid = new Uuid();
-    $this->setValue(array('value' => $uuid->generate()), $notify);
-    return $this;
-  }
-}
diff --git a/core/lib/Drupal/Core/Entity/Plugin/DataType/BooleanItem.php b/core/lib/Drupal/Core/Entity/Plugin/DataType/BooleanItem.php
new file mode 100644
index 0000000..367cc74
--- /dev/null
+++ b/core/lib/Drupal/Core/Entity/Plugin/DataType/BooleanItem.php
@@ -0,0 +1,48 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Entity\Plugin\DataType\BooleanItem.
+ */
+
+namespace Drupal\Core\Entity\Plugin\DataType;
+
+use Drupal\Core\TypedData\Annotation\DataType;
+use Drupal\Core\Annotation\Translation;
+use Drupal\Core\Entity\Field\FieldItemBase;
+
+/**
+ * Defines the 'boolean_field' entity field item.
+ *
+ * @DataType(
+ *   id = "boolean_field",
+ *   label = @Translation("Boolean field item"),
+ *   description = @Translation("An entity field containing a boolean value."),
+ *   list_class = "\Drupal\Core\Entity\Field\Field"
+ * )
+ */
+class BooleanItem extends FieldItemBase {
+
+  /**
+   * Definitions of the contained properties.
+   *
+   * @see BooleanItem::getPropertyDefinitions()
+   *
+   * @var array
+   */
+  static $propertyDefinitions;
+
+  /**
+   * Implements \Drupal\Core\TypedData\ComplexDataInterface::getPropertyDefinitions().
+   */
+  public function getPropertyDefinitions() {
+
+    if (!isset(static::$propertyDefinitions)) {
+      static::$propertyDefinitions['value'] = array(
+        'type' => 'boolean',
+        'label' => t('Boolean value'),
+      );
+    }
+    return static::$propertyDefinitions;
+  }
+}
diff --git a/core/lib/Drupal/Core/Entity/Plugin/DataType/DateItem.php b/core/lib/Drupal/Core/Entity/Plugin/DataType/DateItem.php
new file mode 100644
index 0000000..3fd9aa6
--- /dev/null
+++ b/core/lib/Drupal/Core/Entity/Plugin/DataType/DateItem.php
@@ -0,0 +1,48 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Entity\Plugin\DataType\DateItem.
+ */
+
+namespace Drupal\Core\Entity\Plugin\DataType;
+
+use Drupal\Core\TypedData\Annotation\DataType;
+use Drupal\Core\Annotation\Translation;
+use Drupal\Core\Entity\Field\FieldItemBase;
+
+/**
+ * Defines the 'date_field' entity field item.
+ *
+ * @DataType(
+ *   id = "date_field",
+ *   label = @Translation("Date field item"),
+ *   description = @Translation("An entity field containing a date value."),
+ *   list_class = "\Drupal\Core\Entity\Field\Field"
+ * )
+ */
+class DateItem extends FieldItemBase {
+
+  /**
+   * Definitions of the contained properties.
+   *
+   * @see DateItem::getPropertyDefinitions()
+   *
+   * @var array
+   */
+  static $propertyDefinitions;
+
+  /**
+   * Implements \Drupal\Core\TypedData\ComplexDataInterface::getPropertyDefinitions().
+   */
+  public function getPropertyDefinitions() {
+
+    if (!isset(static::$propertyDefinitions)) {
+      static::$propertyDefinitions['value'] = array(
+        'type' => 'date',
+        'label' => t('Date value'),
+      );
+    }
+    return static::$propertyDefinitions;
+  }
+}
diff --git a/core/lib/Drupal/Core/Entity/Plugin/DataType/EmailItem.php b/core/lib/Drupal/Core/Entity/Plugin/DataType/EmailItem.php
new file mode 100644
index 0000000..b147976
--- /dev/null
+++ b/core/lib/Drupal/Core/Entity/Plugin/DataType/EmailItem.php
@@ -0,0 +1,57 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Entity\Plugin\DataType\EmailItem.
+ */
+
+namespace Drupal\Core\Entity\Plugin\DataType;
+
+use Drupal\Core\TypedData\Annotation\DataType;
+use Drupal\Core\Annotation\Translation;
+use Drupal\Core\Entity\Field\FieldItemBase;
+use Drupal\field\Plugin\field\field_type\LegacyConfigFieldItem;
+
+/**
+ * Defines the 'email_field' entity field item.
+ *
+ * @DataType(
+ *   id = "email_field",
+ *   label = @Translation("E-mail field item"),
+ *   description = @Translation("An entity field containing an e-mail value."),
+ *   list_class = "\Drupal\Core\Entity\Field\Field"
+ * )
+ */
+class EmailItem extends LegacyConfigFieldItem {
+
+  /**
+   * Definitions of the contained properties.
+   *
+   * @see EmailItem::getPropertyDefinitions()
+   *
+   * @var array
+   */
+  static $propertyDefinitions;
+
+  /**
+   * Implements ComplexDataInterface::getPropertyDefinitions().
+   */
+  public function getPropertyDefinitions() {
+
+    if (!isset(static::$propertyDefinitions)) {
+      static::$propertyDefinitions['value'] = array(
+        'type' => 'email',
+        'label' => t('E-mail value'),
+      );
+    }
+    return static::$propertyDefinitions;
+  }
+
+
+  /**
+   * {@inheritdoc}
+   */
+  public function isEmpty() {
+    return !isset($this->values['value']) || $this->values['value'] === '';
+  }
+}
diff --git a/core/lib/Drupal/Core/Entity/Plugin/DataType/EntityReferenceItem.php b/core/lib/Drupal/Core/Entity/Plugin/DataType/EntityReferenceItem.php
new file mode 100644
index 0000000..7f756ad
--- /dev/null
+++ b/core/lib/Drupal/Core/Entity/Plugin/DataType/EntityReferenceItem.php
@@ -0,0 +1,114 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Entity\Plugin\DataType\EntityReferenceItem.
+ */
+
+namespace Drupal\Core\Entity\Plugin\DataType;
+
+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.
+ *
+ * Required settings (below the definition's 'settings' key) are:
+ *  - target_type: The entity type to reference.
+ *
+ * @DataType(
+ *   id = "entity_reference_field",
+ *   label = @Translation("Entity reference field item"),
+ *   description = @Translation("An entity field containing an entity reference."),
+ *   list_class = "\Drupal\Core\Entity\Field\Field"
+ * )
+ */
+class EntityReferenceItem extends FieldItemBase {
+
+  /**
+   * Definitions of the contained properties.
+   *
+   * @see EntityReferenceItem::getPropertyDefinitions()
+   *
+   * @var array
+   */
+  static $propertyDefinitions;
+
+  /**
+   * 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'];
+
+    if (!isset(self::$propertyDefinitions[$target_type])) {
+      static::$propertyDefinitions[$target_type]['target_id'] = array(
+        // @todo: Lookup the entity type's ID data type and use it here.
+        'type' => 'integer',
+        'label' => t('Entity ID'),
+        'constraints' => array(
+          'Range' => array('min' => 0),
+        ),
+      );
+      static::$propertyDefinitions[$target_type]['entity'] = array(
+        'type' => 'entity',
+        'constraints' => array(
+          'EntityType' => $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'),
+      );
+    }
+    return static::$propertyDefinitions[$target_type];
+  }
+
+  /**
+   * Overrides \Drupal\Core\Entity\Field\FieldItemBase::__get().
+   */
+  public function __get($name) {
+    $name = ($name == 'value') ? 'target_id' : $name;
+    return parent::__get($name);
+  }
+
+  /**
+   * Overrides \Drupal\Core\Entity\Field\FieldItemBase::get().
+   */
+  public function get($property_name) {
+    $property_name = ($property_name == 'value') ? 'target_id' : $property_name;
+    return parent::get($property_name);
+  }
+
+  /**
+   * Implements \Drupal\Core\Entity\Field\FieldItemInterface::__isset().
+   */
+  public function __isset($property_name) {
+    $property_name = ($property_name == 'value') ? 'target_id' : $property_name;
+    return parent::__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.
+      $this->properties['entity']->setValue($values, $notify);
+    }
+    else {
+      // Make sure that the 'entity' property gets set as 'target_id'.
+      if (isset($values['target_id']) && !isset($values['entity'])) {
+        $values['entity'] = $values['target_id'];
+      }
+      parent::setValue($values, $notify);
+    }
+  }
+}
diff --git a/core/lib/Drupal/Core/Entity/Plugin/DataType/EntityTranslation.php b/core/lib/Drupal/Core/Entity/Plugin/DataType/EntityTranslation.php
new file mode 100644
index 0000000..8a39126
--- /dev/null
+++ b/core/lib/Drupal/Core/Entity/Plugin/DataType/EntityTranslation.php
@@ -0,0 +1,231 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Entity\Plugin\DataType\EntityTranslation.
+ */
+
+namespace Drupal\Core\Entity\Plugin\DataType;
+
+use Drupal\Core\TypedData\Annotation\DataType;
+use Drupal\Core\Annotation\Translation;
+use Drupal\Core\Session\AccountInterface;
+use Drupal\Core\TypedData\AccessibleInterface;
+use Drupal\Core\TypedData\ComplexDataInterface;
+use Drupal\Core\TypedData\TypedData;
+use ArrayIterator;
+use IteratorAggregate;
+use InvalidArgumentException;
+
+/**
+ * Allows accessing and updating translated entity fields.
+ *
+ * Via this object translated entity fields may be read and updated in the same
+ * way as untranslatable entity fields on the entity object.
+ *
+ * @DataType(
+ *   id = "entity_translation",
+ *   label = @Translation("Entity translation"),
+ *   description = @Translation("A translation of an entity.")
+ * )
+ */
+class EntityTranslation extends TypedData implements IteratorAggregate, AccessibleInterface, ComplexDataInterface {
+
+  /**
+   * The array of translated fields, each being an instance of
+   * \Drupal\Core\Entity\FieldInterface.
+   *
+   * @var array
+   */
+  protected $fields = array();
+
+  /**
+   * Whether the entity translation acts in strict mode.
+   *
+   * @var boolean
+   */
+  protected $strict = TRUE;
+
+  /**
+   * Returns whether the entity translation acts in strict mode.
+   *
+   * @return boolean
+   *   Whether the entity translation acts in strict mode.
+   */
+  public function getStrictMode() {
+    return $this->strict;
+  }
+
+  /**
+   * Sets whether the entity translation acts in strict mode.
+   *
+   * @param boolean $strict
+   *   Whether the entity translation acts in strict mode.
+   *
+   * @see \Drupal\Core\TypedData\TranslatableInterface::getTranslation()
+   */
+  public function setStrictMode($strict = TRUE) {
+    $this->strict = $strict;
+  }
+
+  /**
+   * Overrides \Drupal\Core\TypedData\TypedData::getValue().
+   */
+  public function getValue() {
+    // The plain value of the translation is the array of translated field
+    // objects.
+    return $this->fields;
+  }
+
+  /**
+   * Overrides \Drupal\Core\TypedData\TypedData::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);
+    }
+    $this->fields = $values;
+  }
+
+  /**
+   * Overrides \Drupal\Core\TypedData\TypedData::getString().
+   */
+  public function getString() {
+    $strings = array();
+    foreach ($this->getProperties() as $property) {
+      $strings[] = $property->getString();
+    }
+    return implode(', ', array_filter($strings));
+  }
+
+  /**
+   * Implements \Drupal\Core\TypedData\ComplexDataInterface::get().
+   */
+  public function get($property_name) {
+    $definitions = $this->getPropertyDefinitions();
+    if (!isset($definitions[$property_name])) {
+      throw new InvalidArgumentException(format_string('Field @name is unknown or not translatable.', array('@name' => $property_name)));
+    }
+    return $this->fields[$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) {
+    $properties = array();
+    foreach ($this->getPropertyDefinitions() as $name => $definition) {
+      if ($include_computed || empty($definition['computed'])) {
+        $properties[$name] = $this->get($name);
+      }
+    }
+    return $properties;
+  }
+
+  /**
+   * Magic method: Gets a translated field.
+   */
+  public function __get($name) {
+    return $this->get($name);
+  }
+
+  /**
+   * Magic method: Sets a translated field.
+   */
+  public function __set($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::getPropertyDefinitions().
+   */
+  public function getPropertyDefinitions() {
+    $definitions = array();
+    foreach ($this->parent->getPropertyDefinitions() as $name => $definition) {
+      if (!empty($definition['translatable']) || !$this->strict) {
+        $definitions[$name] = $definition;
+      }
+    }
+    return $definitions;
+  }
+
+  /**
+   * 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 \Drupal\Core\TypedData\ComplexDataInterface::isEmpty().
+   */
+  public function isEmpty() {
+    foreach ($this->getProperties() as $property) {
+      if ($property->getValue() !== NULL) {
+        return FALSE;
+      }
+    }
+    return TRUE;
+  }
+
+  /**
+   * 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', AccountInterface $account = NULL) {
+    // Determine the language code of this translation by cutting of the
+    // leading "@" from the property name to get the langcode.
+    // @todo Add a way to set and get the langcode so that's more obvious what
+    // we're doing here.
+    $langcode = substr($this->getName(), 1);
+    return \Drupal::entityManager()
+      ->getAccessController($this->parent->entityType())
+      ->access($this->parent, $operation, $langcode, $account);
+  }
+}
diff --git a/core/lib/Drupal/Core/Entity/Plugin/DataType/EntityWrapper.php b/core/lib/Drupal/Core/Entity/Plugin/DataType/EntityWrapper.php
new file mode 100644
index 0000000..e2561a9
--- /dev/null
+++ b/core/lib/Drupal/Core/Entity/Plugin/DataType/EntityWrapper.php
@@ -0,0 +1,227 @@
+<?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
index 504e427..346b656 100644
--- a/core/lib/Drupal/Core/Entity/Plugin/DataType/FieldDataTypeDerivative.php
+++ b/core/lib/Drupal/Core/Entity/Plugin/DataType/FieldDataTypeDerivative.php
@@ -38,11 +38,6 @@ public function getDerivativeDefinition($derivative_id, array $base_plugin_defin
    */
   public function getDerivativeDefinitions(array $base_plugin_definition) {
     foreach (\Drupal::service('plugin.manager.entity.field.field_type')->getDefinitions() as $plugin_id => $definition) {
-      // Typed data API expects a 'list class' property, but annotations do not
-      // support spaces in property names.
-      $definition['list class'] = $definition['list_class'];
-      unset($definition['list_class']);
-
       $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
new file mode 100644
index 0000000..3b818e7
--- /dev/null
+++ b/core/lib/Drupal/Core/Entity/Plugin/DataType/FieldItem.php
@@ -0,0 +1,27 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Entity\Plugin\DataType\FieldItem.
+ */
+
+namespace Drupal\Core\Entity\Plugin\DataType;
+
+use Drupal\Core\TypedData\Annotation\DataType;
+use Drupal\Core\Annotation\Translation;
+
+/**
+ * Defines the base plugin definition for field type typed data types typedness typitype.
+ *
+ * Typed types? Cool. Typytypetypetypeepytepyt
+ *
+ * @DataType(
+ *   id = "field_item",
+ *   label = @Translation("Field item"),
+ *   list_class = "\Drupal\Core\Entity\Field\Field",
+ *   derivative = "Drupal\Core\Entity\Plugin\DataType\FieldDataTypeDerivative"
+ * )
+ */
+class FieldItem extends PluginBase {
+
+}
diff --git a/core/lib/Drupal/Core/Entity/Plugin/DataType/IntegerItem.php b/core/lib/Drupal/Core/Entity/Plugin/DataType/IntegerItem.php
new file mode 100644
index 0000000..4eb4db3
--- /dev/null
+++ b/core/lib/Drupal/Core/Entity/Plugin/DataType/IntegerItem.php
@@ -0,0 +1,48 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Entity\Plugin\DataType\IntegerItem.
+ */
+
+namespace Drupal\Core\Entity\Plugin\DataType;
+
+use Drupal\Core\TypedData\Annotation\DataType;
+use Drupal\Core\Annotation\Translation;
+use Drupal\Core\Entity\Field\FieldItemBase;
+
+/**
+ * Defines the 'integer_field' entity field item.
+ *
+ * @DataType(
+ *   id = "integer_field",
+ *   label = @Translation("Integer field item"),
+ *   description = @Translation("An entity field containing an integer value."),
+ *   list_class = "\Drupal\Core\Entity\Field\Field"
+ * )
+ */
+class IntegerItem extends FieldItemBase {
+
+  /**
+   * Definitions of the contained properties.
+   *
+   * @see IntegerItem::getPropertyDefinitions()
+   *
+   * @var array
+   */
+  static $propertyDefinitions;
+
+  /**
+   * Implements \Drupal\Core\TypedData\ComplexDataInterface::getPropertyDefinitions().
+   */
+  public function getPropertyDefinitions() {
+
+    if (!isset(static::$propertyDefinitions)) {
+      static::$propertyDefinitions['value'] = array(
+        'type' => 'integer',
+        'label' => t('Integer value'),
+      );
+    }
+    return static::$propertyDefinitions;
+  }
+}
diff --git a/core/lib/Drupal/Core/Entity/Plugin/DataType/LanguageItem.php b/core/lib/Drupal/Core/Entity/Plugin/DataType/LanguageItem.php
new file mode 100644
index 0000000..5338556
--- /dev/null
+++ b/core/lib/Drupal/Core/Entity/Plugin/DataType/LanguageItem.php
@@ -0,0 +1,92 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Entity\Plugin\DataType\LanguageItem.
+ */
+
+namespace Drupal\Core\Entity\Plugin\DataType;
+
+use Drupal\Core\TypedData\Annotation\DataType;
+use Drupal\Core\Annotation\Translation;
+use Drupal\Core\Entity\Field\FieldItemBase;
+use Drupal\Core\Language\Language;
+
+/**
+ * Defines the 'language_field' entity field item.
+ *
+ * @DataType(
+ *   id = "language_field",
+ *   label = @Translation("Language field item"),
+ *   description = @Translation("An entity field referencing a language."),
+ *   list_class = "\Drupal\Core\Entity\Field\Field",
+ *   constraints = {
+ *     "ComplexData" = {
+ *       "value" = {"Length" = {"max" = 12}}
+ *     }
+ *   }
+ * )
+ */
+class LanguageItem extends FieldItemBase {
+
+  /**
+   * Definitions of the contained properties.
+   *
+   * @see LanguageItem::getPropertyDefinitions()
+   *
+   * @var array
+   */
+  static $propertyDefinitions;
+
+  /**
+   * 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',
+        'label' => t('Language object'),
+        // The language object is retrieved via the language code.
+        'computed' => TRUE,
+        'read-only' => FALSE,
+        'settings' => array('langcode source' => 'value'),
+      );
+    }
+    return static::$propertyDefinitions;
+  }
+
+  /**
+   * Overrides \Drupal\Core\Entity\Field\FieldItemBase::get().
+   */
+  public function setValue($values, $notify = TRUE) {
+    // Treat the values as property value of the language property, if no array
+    // is given as this handles language codes and objects.
+    if (isset($values) && !is_array($values)) {
+      // Directly update the property instead of invoking the parent, so that
+      // the language property can take care of updating the language code
+      // property.
+      $this->properties['language']->setValue($values, $notify);
+    }
+    else {
+      // Make sure that the 'language' property gets set as 'value'.
+      if (isset($values['value']) && !isset($values['language'])) {
+        $values['language'] = $values['value'];
+      }
+      parent::setValue($values, $notify);
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function applyDefaultValue($notify = TRUE) {
+    // Default to LANGCODE_NOT_SPECIFIED.
+    $this->setValue(array('value' => Language::LANGCODE_NOT_SPECIFIED), $notify);
+    return $this;
+  }
+}
diff --git a/core/lib/Drupal/Core/Entity/Plugin/DataType/StringItem.php b/core/lib/Drupal/Core/Entity/Plugin/DataType/StringItem.php
new file mode 100644
index 0000000..1f22d49
--- /dev/null
+++ b/core/lib/Drupal/Core/Entity/Plugin/DataType/StringItem.php
@@ -0,0 +1,48 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Entity\Plugin\DataType\StringItem.
+ */
+
+namespace Drupal\Core\Entity\Plugin\DataType;
+
+use Drupal\Core\TypedData\Annotation\DataType;
+use Drupal\Core\Annotation\Translation;
+use Drupal\Core\Entity\Field\FieldItemBase;
+
+/**
+ * Defines the 'string_field' entity field item.
+ *
+ * @DataType(
+ *   id = "string_field",
+ *   label = @Translation("String field item"),
+ *   description = @Translation("An entity field containing a string value."),
+ *   list_class = "\Drupal\Core\Entity\Field\Field"
+ * )
+ */
+class StringItem extends FieldItemBase {
+
+  /**
+   * Definitions of the contained properties.
+   *
+   * @see StringItem::getPropertyDefinitions()
+   *
+   * @var array
+   */
+  static $propertyDefinitions;
+
+  /**
+   * Implements \Drupal\Core\TypedData\ComplexDataInterface::getPropertyDefinitions().
+   */
+  public function getPropertyDefinitions() {
+
+    if (!isset(static::$propertyDefinitions)) {
+      static::$propertyDefinitions['value'] = array(
+        'type' => 'string',
+        'label' => t('Text value'),
+      );
+    }
+    return static::$propertyDefinitions;
+  }
+}
diff --git a/core/lib/Drupal/Core/Entity/Plugin/DataType/UriItem.php b/core/lib/Drupal/Core/Entity/Plugin/DataType/UriItem.php
new file mode 100644
index 0000000..263ec22
--- /dev/null
+++ b/core/lib/Drupal/Core/Entity/Plugin/DataType/UriItem.php
@@ -0,0 +1,48 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Entity\Plugin\DataType\UriItem.
+ */
+
+namespace Drupal\Core\Entity\Plugin\DataType;
+
+use Drupal\Core\TypedData\Annotation\DataType;
+use Drupal\Core\Annotation\Translation;
+use Drupal\Core\Entity\Field\FieldItemBase;
+
+/**
+ * Defines the 'uri_field' entity field item.
+ *
+ * @DataType(
+ *   id = "uri_field",
+ *   label = @Translation("URI field item"),
+ *   description = @Translation("An entity field containing a URI."),
+ *   list_class = "\Drupal\Core\Entity\Field\Field"
+ * )
+ */
+class UriItem extends FieldItemBase {
+
+  /**
+   * Field definitions of the contained properties.
+   *
+   * @see self::getPropertyDefinitions()
+   *
+   * @var array
+   */
+  static $propertyDefinitions;
+
+  /**
+   * Implements ComplexDataInterface::getPropertyDefinitions().
+   */
+  public function getPropertyDefinitions() {
+
+    if (!isset(self::$propertyDefinitions)) {
+      self::$propertyDefinitions['value'] = array(
+        'type' => 'string',
+        'label' => t('Text value'),
+      );
+    }
+    return self::$propertyDefinitions;
+  }
+}
diff --git a/core/lib/Drupal/Core/Entity/Plugin/DataType/UuidItem.php b/core/lib/Drupal/Core/Entity/Plugin/DataType/UuidItem.php
new file mode 100644
index 0000000..737409d
--- /dev/null
+++ b/core/lib/Drupal/Core/Entity/Plugin/DataType/UuidItem.php
@@ -0,0 +1,42 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Entity\Plugin\DataType\UuidItem.
+ */
+
+namespace Drupal\Core\Entity\Plugin\DataType;
+
+use Drupal\Core\TypedData\Annotation\DataType;
+use Drupal\Core\Annotation\Translation;
+use Drupal\Component\Uuid\Uuid;
+
+/**
+ * Defines the 'uuid_field' entity field item.
+ *
+ * The field uses a newly generated UUID as default value.
+ *
+ * @DataType(
+ *   id = "uuid_field",
+ *   label = @Translation("UUID field item"),
+ *   description = @Translation("An entity field containing a UUID."),
+ *   list_class = "\Drupal\Core\Entity\Field\Field",
+ *   constraints = {
+ *     "ComplexData" = {
+ *       "value" = {"Length" = {"max" = 128}}
+ *     }
+ *   }
+ * )
+ */
+class UuidItem extends StringItem {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function applyDefaultValue($notify = TRUE) {
+    // Default to one field item with a generated UUID.
+    $uuid = new Uuid();
+    $this->setValue(array('value' => $uuid->generate()), $notify);
+    return $this;
+  }
+}
diff --git a/core/lib/Drupal/Core/Plugin/Context/Context.php b/core/lib/Drupal/Core/Plugin/Context/Context.php
index cc9f355..3ed6358 100644
--- a/core/lib/Drupal/Core/Plugin/Context/Context.php
+++ b/core/lib/Drupal/Core/Plugin/Context/Context.php
@@ -8,7 +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\Entity\Plugin\DataType\EntityWrapper;
 use Drupal\Core\TypedData\ComplexDataInterface;
 use Drupal\Core\TypedData\ListInterface;
 use Drupal\Core\TypedData\TypedDataInterface;
diff --git a/core/lib/Drupal/Core/TypedData/Annotation/DataType.php b/core/lib/Drupal/Core/TypedData/Annotation/DataType.php
new file mode 100644
index 0000000..946467f
--- /dev/null
+++ b/core/lib/Drupal/Core/TypedData/Annotation/DataType.php
@@ -0,0 +1,35 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\TypedData\Annotation\DataType.
+ */
+
+namespace Drupal\Core\TypedData\Annotation;
+
+use Drupal\Component\Annotation\Plugin;
+
+/**
+ * Defines a data type annotation object.
+ *
+ * @Annotation
+ */
+class DataType extends Plugin {
+
+  /**
+   * The name of the module providing the type.
+   *
+   * @var string
+   */
+  public $module;
+
+  /**
+   * The name of the data type class.
+   *
+   * This is not provided manually, it will be added by the discovery mechanism.
+   *
+   * @var string
+   */
+  public $class;
+
+}
diff --git a/core/lib/Drupal/Core/TypedData/Plugin/DataType/Any.php b/core/lib/Drupal/Core/TypedData/Plugin/DataType/Any.php
new file mode 100644
index 0000000..9236b22
--- /dev/null
+++ b/core/lib/Drupal/Core/TypedData/Plugin/DataType/Any.php
@@ -0,0 +1,34 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\TypedData\Plugin\DataType\Any.
+ */
+
+namespace Drupal\Core\TypedData\Plugin\DataType;
+
+use Drupal\Core\TypedData\Annotation\DataType;
+use Drupal\Core\Annotation\Translation;
+use Drupal\Core\TypedData\TypedData;
+
+/**
+ * The "any" data type.
+ *
+ * The "any" data type does not implement a list or complex data interface, nor
+ * is it mappable to any primitive type. Thus, it may contain any PHP data for
+ * which no further metadata is available.
+ *
+ * @DataType(
+ *   id = "any",
+ *   label = @Translation("Any data")
+ * )
+ */
+class Any extends TypedData {
+
+  /**
+   * The data value.
+   *
+   * @var mixed
+   */
+  protected $value;
+}
diff --git a/core/lib/Drupal/Core/TypedData/Plugin/DataType/Binary.php b/core/lib/Drupal/Core/TypedData/Plugin/DataType/Binary.php
new file mode 100644
index 0000000..05315cf
--- /dev/null
+++ b/core/lib/Drupal/Core/TypedData/Plugin/DataType/Binary.php
@@ -0,0 +1,91 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\TypedData\Plugin\DataType\Binary.
+ */
+
+namespace Drupal\Core\TypedData\Plugin\DataType;
+
+use Drupal\Core\TypedData\Annotation\DataType;
+use Drupal\Core\Annotation\Translation;
+use Drupal\Core\TypedData\TypedData;
+
+/**
+ * The binary data type.
+ *
+ * The plain value of binary data is a PHP file resource, see
+ * http://php.net/manual/en/language.types.resource.php. For setting the value
+ * a PHP file resource or a (absolute) stream resource URI may be passed.
+ *
+ * @DataType(
+ *   id = "binary",
+ *   label = @Translation("Binary"),
+ *   primitive_type = 8
+ * )
+ */
+class Binary extends TypedData {
+
+  /**
+   * The file resource URI.
+   *
+   * @var string
+   */
+  protected $uri;
+
+  /**
+   * A generic file resource handle.
+   *
+   * @var resource
+   */
+  public $handle = NULL;
+
+  /**
+   * Overrides TypedData::getValue().
+   */
+  public function getValue() {
+    // If the value has been set by (absolute) stream resource URI, access the
+    // resource now.
+    if (!isset($this->handle) && isset($this->uri)) {
+      $this->handle = is_readable($this->uri) ? fopen($this->uri, 'rb') : FALSE;
+    }
+    return $this->handle;
+  }
+
+  /**
+   * Overrides TypedData::setValue().
+   *
+   * 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;
+    }
+    elseif (is_string($value)) {
+      // Note: For performance reasons we store the given URI and access the
+      // resource upon request. See Binary::getValue()
+      $this->uri = $value;
+      $this->handle = NULL;
+    }
+    else {
+      $this->handle = $value;
+    }
+  }
+
+  /**
+   * Overrides TypedData::getString().
+   */
+  public function getString() {
+    // Return the file content.
+    $contents = '';
+    while (!feof($this->getValue())) {
+      $contents .= fread($this->handle, 8192);
+    }
+    return $contents;
+  }
+}
diff --git a/core/lib/Drupal/Core/TypedData/Plugin/DataType/Boolean.php b/core/lib/Drupal/Core/TypedData/Plugin/DataType/Boolean.php
new file mode 100644
index 0000000..6eddffd
--- /dev/null
+++ b/core/lib/Drupal/Core/TypedData/Plugin/DataType/Boolean.php
@@ -0,0 +1,34 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\TypedData\Plugin\DataType\Boolean.
+ */
+
+namespace Drupal\Core\TypedData\Plugin\DataType;
+
+use Drupal\Core\TypedData\Annotation\DataType;
+use Drupal\Core\Annotation\Translation;
+use Drupal\Core\TypedData\TypedData;
+
+/**
+ * The boolean data type.
+ *
+ * The plain value of a boolean is a regular PHP boolean. For setting the value
+ * any PHP variable that casts to a boolean may be passed.
+ *
+ * @DataType(
+ *   id = "boolean",
+ *   label = @Translation("Boolean"),
+ *   primitive_type = 1
+ * )
+ */
+class Boolean extends TypedData {
+
+  /**
+   * The data value.
+   *
+   * @var boolean
+   */
+  protected $value;
+}
diff --git a/core/lib/Drupal/Core/TypedData/Plugin/DataType/Date.php b/core/lib/Drupal/Core/TypedData/Plugin/DataType/Date.php
new file mode 100644
index 0000000..96a7db8
--- /dev/null
+++ b/core/lib/Drupal/Core/TypedData/Plugin/DataType/Date.php
@@ -0,0 +1,55 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\TypedData\Plugin\DataType\Date.
+ */
+
+namespace Drupal\Core\TypedData\Plugin\DataType;
+
+use Drupal\Core\TypedData\Annotation\DataType;
+use Drupal\Core\Annotation\Translation;
+use Drupal\Core\Datetime\DrupalDateTime;
+use Drupal\Core\TypedData\TypedData;
+
+/**
+ * The date data type.
+ *
+ * The plain value of a date is an instance of the DrupalDateTime class. For
+ * setting the value any value supported by the __construct() of the
+ * DrupalDateTime class will work, including a DateTime object, a timestamp, a
+ * string date, or an array of date parts.
+ *
+ * @DataType(
+ *   id = "date",
+ *   label = @Translation("Date"),
+ *   primitive_type = 5
+ * )
+ */
+class Date extends TypedData {
+
+  /**
+   * The data value.
+   *
+   * @var DateTime
+   */
+  protected $value;
+
+  /**
+   * Overrides TypedData::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);
+    }
+    // Don't try to create a date from an empty value.
+    // It would default to the current time.
+    if (!isset($value)) {
+      $this->value = $value;
+    }
+    else {
+      $this->value = $value instanceOf DrupalDateTime ? $value : new DrupalDateTime($value);
+    }
+  }
+}
diff --git a/core/lib/Drupal/Core/TypedData/Plugin/DataType/Duration.php b/core/lib/Drupal/Core/TypedData/Plugin/DataType/Duration.php
new file mode 100644
index 0000000..575a4c3
--- /dev/null
+++ b/core/lib/Drupal/Core/TypedData/Plugin/DataType/Duration.php
@@ -0,0 +1,81 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\TypedData\Plugin\DataType\Duration.
+ */
+
+namespace Drupal\Core\TypedData\Plugin\DataType;
+
+use Drupal\Core\TypedData\Annotation\DataType;
+use Drupal\Core\Annotation\Translation;
+use Drupal\Core\TypedData\TypedData;
+use DateInterval;
+
+/**
+ * The duration data type.
+ *
+ * The plain value of a duration is an instance of the DateInterval class. For
+ * setting the value an instance of the DateInterval class, a ISO8601 string as
+ * supported by DateInterval::__construct, or an integer in seconds may be
+ * passed.
+ *
+ * @DataType(
+ *   id = "duration",
+ *   label = @Translation("Duration"),
+ *   primitive_type = 6
+ * )
+ */
+class Duration extends TypedData {
+
+  /**
+   * The data value.
+   *
+   * @var \DateInterval
+   */
+  protected $value;
+
+  /**
+   * Overrides TypedData::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);
+    }
+    // Catch any exceptions thrown due to invalid values being passed.
+    try {
+      if ($value instanceof DateInterval || !isset($value)) {
+        $this->value = $value;
+      }
+      // Treat integer values as time spans in seconds, even if supplied as PHP
+      // string.
+      elseif ((string) (int) $value === (string) $value) {
+        $this->value = new DateInterval('PT' . $value . 'S');
+      }
+      elseif (is_string($value)) {
+        // @todo: Add support for negative intervals on top of the DateInterval
+        // constructor.
+        $this->value = new DateInterval($value);
+      }
+      else {
+        // Unknown value given.
+        $this->value = $value;
+      }
+    }
+    catch (\Exception $e) {
+      // An invalid value has been given. Setting any invalid value will let
+      // validation fail.
+      $this->value = $e;
+    }
+  }
+
+  /**
+   * Overrides TypedData::getString().
+   */
+  public function getString() {
+    // Generate an ISO 8601 formatted string as supported by
+    // DateInterval::__construct() and setValue().
+    return (string) $this->getValue()->format('%rP%yY%mM%dDT%hH%mM%sS');
+  }
+}
diff --git a/core/lib/Drupal/Core/TypedData/Plugin/DataType/Email.php b/core/lib/Drupal/Core/TypedData/Plugin/DataType/Email.php
new file mode 100644
index 0000000..829929d
--- /dev/null
+++ b/core/lib/Drupal/Core/TypedData/Plugin/DataType/Email.php
@@ -0,0 +1,27 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\TypedData\Plugin\DataType\Email.
+ */
+
+namespace Drupal\Core\TypedData\Plugin\DataType;
+
+use Drupal\Core\TypedData\Annotation\DataType;
+use Drupal\Core\Annotation\Translation;
+
+/**
+ * The Email data type.
+ *
+ * The plain value of Email is the email address represented as PHP string.
+ *
+ * @DataType(
+ *   id = "email",
+ *   label = @Translation("Email"),
+ *   primitive_type = 2,
+ *   constraints = {"Email" = TRUE}
+ * )
+ */
+class Email extends String {
+
+}
diff --git a/core/lib/Drupal/Core/TypedData/Plugin/DataType/Float.php b/core/lib/Drupal/Core/TypedData/Plugin/DataType/Float.php
new file mode 100644
index 0000000..35a05c8
--- /dev/null
+++ b/core/lib/Drupal/Core/TypedData/Plugin/DataType/Float.php
@@ -0,0 +1,34 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\TypedData\Plugin\DataType\Float.
+ */
+
+namespace Drupal\Core\TypedData\Plugin\DataType;
+
+use Drupal\Core\TypedData\Annotation\DataType;
+use Drupal\Core\Annotation\Translation;
+use Drupal\Core\TypedData\TypedData;
+
+/**
+ * The float data type.
+ *
+ * The plain value of a float is a regular PHP float. For setting the value
+ * any PHP variable that casts to a float may be passed.
+ *
+ * @DataType(
+ *   id = "float",
+ *   label = @Translation("Float"),
+ *   primitive_type = 4
+ * )
+ */
+class Float extends TypedData {
+
+  /**
+   * The data value.
+   *
+   * @var float
+   */
+  protected $value;
+}
diff --git a/core/lib/Drupal/Core/TypedData/Plugin/DataType/Integer.php b/core/lib/Drupal/Core/TypedData/Plugin/DataType/Integer.php
new file mode 100644
index 0000000..59070b8
--- /dev/null
+++ b/core/lib/Drupal/Core/TypedData/Plugin/DataType/Integer.php
@@ -0,0 +1,34 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\TypedData\Plugin\DataType\Integer.
+ */
+
+namespace Drupal\Core\TypedData\Plugin\DataType;
+
+use Drupal\Core\TypedData\Annotation\DataType;
+use Drupal\Core\Annotation\Translation;
+use Drupal\Core\TypedData\TypedData;
+
+/**
+ * The integer data type.
+ *
+ * The plain value of an integer is a regular PHP integer. For setting the value
+ * any PHP variable that casts to an integer may be passed.
+ *
+ * @DataType(
+ *   id = "integer",
+ *   label = @Translation("Integer"),
+ *   primitive_type = 3
+ * )
+ */
+class Integer extends TypedData {
+
+  /**
+   * The data value.
+   *
+   * @var integer
+   */
+  protected $value;
+}
diff --git a/core/lib/Drupal/Core/TypedData/Plugin/DataType/Language.php b/core/lib/Drupal/Core/TypedData/Plugin/DataType/Language.php
new file mode 100644
index 0000000..527a2a7
--- /dev/null
+++ b/core/lib/Drupal/Core/TypedData/Plugin/DataType/Language.php
@@ -0,0 +1,91 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\TypedData\Plugin\DataType\Language.
+ */
+
+namespace Drupal\Core\TypedData\Plugin\DataType;
+
+use Drupal\Core\TypedData\Annotation\DataType;
+use Drupal\Core\Annotation\Translation;
+use InvalidArgumentException;
+use Drupal\Core\Language\Language as LanguageObject;
+use Drupal\Core\TypedData\TypedData;
+
+/**
+ * Defines the 'language' data type.
+ *
+ * The plain value of a language 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.
+ *
+ * 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 {
+
+  /**
+   * The language code of the language if no 'langcode source' is used.
+   *
+   * @var string
+   */
+  protected $langcode;
+
+  /**
+   * Overrides TypedData::getValue().
+   */
+  public function getValue() {
+    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));
+    }
+  }
+
+  /**
+   * Overrides TypedData::setValue().
+   *
+   * Both the langcode and the language object may be passed as value.
+   */
+  public function setValue($value, $notify = TRUE) {
+    // Support passing language objects.
+    if (is_object($value)) {
+      $value = $value->langcode;
+    }
+    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->langcode = $value;
+    }
+  }
+
+  /**
+   * Overrides TypedData::getString().
+   */
+  public function getString() {
+    $language = $this->getValue();
+    return $language ? $language->name : '';
+  }
+}
diff --git a/core/lib/Drupal/Core/TypedData/Plugin/DataType/Map.php b/core/lib/Drupal/Core/TypedData/Plugin/DataType/Map.php
new file mode 100644
index 0000000..a033322
--- /dev/null
+++ b/core/lib/Drupal/Core/TypedData/Plugin/DataType/Map.php
@@ -0,0 +1,250 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\TypedData\Plugin\DataType\Map.
+ */
+
+namespace Drupal\Core\TypedData\Plugin\DataType;
+
+use Drupal\Core\TypedData\Annotation\DataType;
+use Drupal\Core\Annotation\Translation;
+use Drupal\Core\TypedData\TypedData;
+use Drupal\Core\TypedData\ComplexDataInterface;
+
+/**
+ * The "map" data type.
+ *
+ * The "map" data type represent a simple complex data type, e.g. for
+ * representing associative arrays. It can also serve as base class for any
+ * complex data type.
+ *
+ * By default there is no metadata for contained properties. Extending classes
+ * may want to override Map::getPropertyDefinitions() to define it.
+ *
+ * @DataType(
+ *   id = "map",
+ *   label = @Translation("Map")
+ * )
+ */
+class Map extends TypedData implements \IteratorAggregate, ComplexDataInterface {
+
+  /**
+   * An array of values for the contained properties.
+   *
+   * @var array
+   */
+  protected $values = array();
+
+  /**
+   * The array of properties, each implementing the TypedDataInterface.
+   *
+   * @var array
+   */
+  protected $properties = array();
+
+  /**
+   * Implements \Drupal\Core\TypedData\ComplexDataInterface::getPropertyDefinitions().
+   */
+  public function getPropertyDefinitions() {
+    $definitions = array();
+    foreach ($this->values as $name => $value) {
+      $definitions[$name] = array(
+        'type' => 'any',
+      );
+    }
+    return $definitions;
+  }
+
+  /**
+   * Overrides \Drupal\Core\TypedData\TypedData::getValue().
+   */
+  public function getValue($include_computed = FALSE) {
+    // Update the values and return them.
+    foreach ($this->properties as $name => $property) {
+      $definition = $property->getDefinition();
+      if ($include_computed || empty($definition['computed'])) {
+        $value = $property->getValue();
+        // Only write NULL values if the whole map is not NULL.
+        if (isset($this->values) || isset($value)) {
+          $this->values[$name] = $value;
+        }
+      }
+    }
+    return $this->values;
+  }
+
+  /**
+   * Overrides \Drupal\Core\TypedData\TypedData::setValue().
+   *
+   * @param array|null $values
+   *   An array of property 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;
+
+    // Update any existing property objects.
+    foreach ($this->properties as $name => $property) {
+      $value = NULL;
+      if (isset($values[$name])) {
+        $value = $values[$name];
+      }
+      $property->setValue($value, FALSE);
+    }
+  }
+
+  /**
+   * Overrides \Drupal\Core\TypedData\TypedData::getString().
+   */
+  public function getString() {
+    $strings = array();
+    foreach ($this->getProperties() as $property) {
+      $strings[] = $property->getString();
+    }
+    // Remove any empty strings resulting from empty items.
+    return implode(', ', array_filter($strings, 'drupal_strlen'));
+  }
+
+  /**
+   * Implements \Drupal\Core\TypedData\ComplexDataInterface::get().
+   */
+  public function get($property_name) {
+    if (!isset($this->properties[$property_name])) {
+      $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] = \Drupal::typedData()->getPropertyInstance($this, $property_name, $value);
+    }
+    return $this->properties[$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);
+    }
+    else {
+      // Just set the plain value, which allows adding a new entry to the map.
+      $this->values[$property_name] = $value;
+    }
+  }
+
+  /**
+   * 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->get($name);
+      }
+    }
+    return $properties;
+  }
+
+  /**
+   * Implements \Drupal\Core\TypedData\ComplexDataInterface::getPropertyValues().
+   */
+  public function getPropertyValues() {
+    $values = array();
+    foreach ($this->getProperties() as $name => $property) {
+      $values[$name] = $property->getValue();
+    }
+    return $values;
+  }
+
+  /**
+   * 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->properties as $property) {
+      $definition = $property->getDefinition();
+      if (empty($definition['computed']) && $property->getValue() !== NULL) {
+        return FALSE;
+      }
+    }
+    if (isset($this->values)) {
+      foreach ($this->values as $name => $value) {
+        if (isset($value) && !isset($this->properties[$name])) {
+          return FALSE;
+        }
+      }
+    }
+    return TRUE;
+  }
+
+  /**
+   * Magic method: Implements a deep clone.
+   */
+  public function __clone() {
+    foreach ($this->properties as $name => $property) {
+      $this->properties[$name] = clone $property;
+      $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);
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function applyDefaultValue($notify = TRUE) {
+    // Apply the default value of all properties.
+    foreach ($this->getProperties() as $property) {
+      $property->applyDefaultValue(FALSE);
+    }
+    return $this;
+  }
+}
diff --git a/core/lib/Drupal/Core/TypedData/Plugin/DataType/String.php b/core/lib/Drupal/Core/TypedData/Plugin/DataType/String.php
new file mode 100644
index 0000000..4ed28b5
--- /dev/null
+++ b/core/lib/Drupal/Core/TypedData/Plugin/DataType/String.php
@@ -0,0 +1,34 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\TypedData\Plugin\DataType\String.
+ */
+
+namespace Drupal\Core\TypedData\Plugin\DataType;
+
+use Drupal\Core\TypedData\Annotation\DataType;
+use Drupal\Core\Annotation\Translation;
+use Drupal\Core\TypedData\TypedData;
+
+/**
+ * The string data type.
+ *
+ * The plain value of a string is a regular PHP string. For setting the value
+ * any PHP variable that casts to a string may be passed.
+ *
+ * @DataType(
+ *   id = "string",
+ *   label = @Translation("String"),
+ *   primitive_type = 2
+ * )
+ */
+class String extends TypedData {
+
+  /**
+   * The data value.
+   *
+   * @var string
+   */
+  protected $value;
+}
diff --git a/core/lib/Drupal/Core/TypedData/Plugin/DataType/Uri.php b/core/lib/Drupal/Core/TypedData/Plugin/DataType/Uri.php
new file mode 100644
index 0000000..bd45a32
--- /dev/null
+++ b/core/lib/Drupal/Core/TypedData/Plugin/DataType/Uri.php
@@ -0,0 +1,33 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\TypedData\Plugin\DataType\Uri.
+ */
+
+namespace Drupal\Core\TypedData\Plugin\DataType;
+
+use Drupal\Core\TypedData\Annotation\DataType;
+use Drupal\Core\Annotation\Translation;
+use Drupal\Core\TypedData\TypedData;
+
+/**
+ * The URI data type.
+ *
+ * The plain value of a URI is an absolute URI represented as PHP string.
+ *
+ * @DataType(
+ *   id = "uri",
+ *   label = @Translation("URI"),
+ *   primitive_type = 7
+ * )
+ */
+class Uri extends TypedData {
+
+  /**
+   * The data value.
+   *
+   * @var string
+   */
+  protected $value;
+}
diff --git a/core/lib/Drupal/Core/TypedData/Type/Any.php b/core/lib/Drupal/Core/TypedData/Type/Any.php
deleted file mode 100644
index 21afa99..0000000
--- a/core/lib/Drupal/Core/TypedData/Type/Any.php
+++ /dev/null
@@ -1,27 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\Core\TypedData\Type\Any.
- */
-
-namespace Drupal\Core\TypedData\Type;
-
-use Drupal\Core\TypedData\TypedData;
-
-/**
- * The "any" data type.
- *
- * The "any" data type does not implement a list or complex data interface, nor
- * is it mappable to any primitive type. Thus, it may contain any PHP data for
- * which no further metadata is available.
- */
-class Any extends TypedData {
-
-  /**
-   * The data value.
-   *
-   * @var mixed
-   */
-  protected $value;
-}
diff --git a/core/lib/Drupal/Core/TypedData/Type/Binary.php b/core/lib/Drupal/Core/TypedData/Type/Binary.php
deleted file mode 100644
index f9c4985..0000000
--- a/core/lib/Drupal/Core/TypedData/Type/Binary.php
+++ /dev/null
@@ -1,84 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\Core\TypedData\Type\Binary.
- */
-
-namespace Drupal\Core\TypedData\Type;
-
-use Drupal\Core\TypedData\TypedData;
-use InvalidArgumentException;
-
-/**
- * The binary data type.
- *
- * The plain value of binary data is a PHP file resource, see
- * http://php.net/manual/en/language.types.resource.php. For setting the value
- * a PHP file resource or a (absolute) stream resource URI may be passed.
- */
-class Binary extends TypedData {
-
-  /**
-   * The file resource URI.
-   *
-   * @var string
-   */
-  protected $uri;
-
-  /**
-   * A generic file resource handle.
-   *
-   * @var resource
-   */
-  public $handle = NULL;
-
-  /**
-   * Overrides TypedData::getValue().
-   */
-  public function getValue() {
-    // If the value has been set by (absolute) stream resource URI, access the
-    // resource now.
-    if (!isset($this->handle) && isset($this->uri)) {
-      $this->handle = is_readable($this->uri) ? fopen($this->uri, 'rb') : FALSE;
-    }
-    return $this->handle;
-  }
-
-  /**
-   * Overrides TypedData::setValue().
-   *
-   * 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;
-    }
-    elseif (is_string($value)) {
-      // Note: For performance reasons we store the given URI and access the
-      // resource upon request. See Binary::getValue()
-      $this->uri = $value;
-      $this->handle = NULL;
-    }
-    else {
-      $this->handle = $value;
-    }
-  }
-
-  /**
-   * Overrides TypedData::getString().
-   */
-  public function getString() {
-    // Return the file content.
-    $contents = '';
-    while (!feof($this->getValue())) {
-      $contents .= fread($this->handle, 8192);
-    }
-    return $contents;
-  }
-}
diff --git a/core/lib/Drupal/Core/TypedData/Type/Boolean.php b/core/lib/Drupal/Core/TypedData/Type/Boolean.php
deleted file mode 100644
index 6c357c9..0000000
--- a/core/lib/Drupal/Core/TypedData/Type/Boolean.php
+++ /dev/null
@@ -1,26 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\Core\TypedData\Type\Boolean.
- */
-
-namespace Drupal\Core\TypedData\Type;
-
-use Drupal\Core\TypedData\TypedData;
-
-/**
- * The boolean data type.
- *
- * The plain value of a boolean is a regular PHP boolean. For setting the value
- * any PHP variable that casts to a boolean may be passed.
- */
-class Boolean extends TypedData {
-
-  /**
-   * The data value.
-   *
-   * @var boolean
-   */
-  protected $value;
-}
diff --git a/core/lib/Drupal/Core/TypedData/Type/Date.php b/core/lib/Drupal/Core/TypedData/Type/Date.php
deleted file mode 100644
index c9b8c6b..0000000
--- a/core/lib/Drupal/Core/TypedData/Type/Date.php
+++ /dev/null
@@ -1,48 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\Core\TypedData\Type\Date.
- */
-
-namespace Drupal\Core\TypedData\Type;
-
-use Drupal\Core\Datetime\DrupalDateTime;
-use Drupal\Core\TypedData\TypedData;
-use InvalidArgumentException;
-
-/**
- * The date data type.
- *
- * The plain value of a date is an instance of the DrupalDateTime class. For
- * setting the value any value supported by the __construct() of the
- * DrupalDateTime class will work, including a DateTime object, a timestamp, a
- * string date, or an array of date parts.
- */
-class Date extends TypedData {
-
-  /**
-   * The data value.
-   *
-   * @var DateTime
-   */
-  protected $value;
-
-  /**
-   * Overrides TypedData::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);
-    }
-    // Don't try to create a date from an empty value.
-    // It would default to the current time.
-    if (!isset($value)) {
-      $this->value = $value;
-    }
-    else {
-      $this->value = $value instanceOf DrupalDateTime ? $value : new DrupalDateTime($value);
-    }
-  }
-}
diff --git a/core/lib/Drupal/Core/TypedData/Type/Duration.php b/core/lib/Drupal/Core/TypedData/Type/Duration.php
deleted file mode 100644
index 52ba97d..0000000
--- a/core/lib/Drupal/Core/TypedData/Type/Duration.php
+++ /dev/null
@@ -1,74 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\Core\TypedData\Type\Duration.
- */
-
-namespace Drupal\Core\TypedData\Type;
-
-use Drupal\Core\TypedData\TypedData;
-use DateInterval;
-use InvalidArgumentException;
-
-/**
- * The duration data type.
- *
- * The plain value of a duration is an instance of the DateInterval class. For
- * setting the value an instance of the DateInterval class, a ISO8601 string as
- * supported by DateInterval::__construct, or an integer in seconds may be
- * passed.
- */
-class Duration extends TypedData {
-
-  /**
-   * The data value.
-   *
-   * @var \DateInterval
-   */
-  protected $value;
-
-  /**
-   * Overrides TypedData::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);
-    }
-    // Catch any exceptions thrown due to invalid values being passed.
-    try {
-      if ($value instanceof DateInterval || !isset($value)) {
-        $this->value = $value;
-      }
-      // Treat integer values as time spans in seconds, even if supplied as PHP
-      // string.
-      elseif ((string) (int) $value === (string) $value) {
-        $this->value = new DateInterval('PT' . $value . 'S');
-      }
-      elseif (is_string($value)) {
-        // @todo: Add support for negative intervals on top of the DateInterval
-        // constructor.
-        $this->value = new DateInterval($value);
-      }
-      else {
-        // Unknown value given.
-        $this->value = $value;
-      }
-    }
-    catch (\Exception $e) {
-      // An invalid value has been given. Setting any invalid value will let
-      // validation fail.
-      $this->value = $e;
-    }
-  }
-
-  /**
-   * Overrides TypedData::getString().
-   */
-  public function getString() {
-    // Generate an ISO 8601 formatted string as supported by
-    // DateInterval::__construct() and setValue().
-    return (string) $this->getValue()->format('%rP%yY%mM%dDT%hH%mM%sS');
-  }
-}
diff --git a/core/lib/Drupal/Core/TypedData/Type/Email.php b/core/lib/Drupal/Core/TypedData/Type/Email.php
deleted file mode 100644
index 314f8f5..0000000
--- a/core/lib/Drupal/Core/TypedData/Type/Email.php
+++ /dev/null
@@ -1,17 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\Core\TypedData\Type\Email.
- */
-
-namespace Drupal\Core\TypedData\Type;
-
-/**
- * The Email data type.
- *
- * The plain value of Email is the email address represented as PHP string.
- */
-class Email extends String {
-
-}
diff --git a/core/lib/Drupal/Core/TypedData/Type/Float.php b/core/lib/Drupal/Core/TypedData/Type/Float.php
deleted file mode 100644
index 482cad1..0000000
--- a/core/lib/Drupal/Core/TypedData/Type/Float.php
+++ /dev/null
@@ -1,26 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\Core\TypedData\Type\Float.
- */
-
-namespace Drupal\Core\TypedData\Type;
-
-use Drupal\Core\TypedData\TypedData;
-
-/**
- * The float data type.
- *
- * The plain value of a float is a regular PHP float. For setting the value
- * any PHP variable that casts to a float may be passed.
- */
-class Float extends TypedData {
-
-  /**
-   * The data value.
-   *
-   * @var float
-   */
-  protected $value;
-}
diff --git a/core/lib/Drupal/Core/TypedData/Type/Integer.php b/core/lib/Drupal/Core/TypedData/Type/Integer.php
deleted file mode 100644
index eb6336e..0000000
--- a/core/lib/Drupal/Core/TypedData/Type/Integer.php
+++ /dev/null
@@ -1,26 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\Core\TypedData\Type\Integer.
- */
-
-namespace Drupal\Core\TypedData\Type;
-
-use Drupal\Core\TypedData\TypedData;
-
-/**
- * The integer data type.
- *
- * The plain value of an integer is a regular PHP integer. For setting the value
- * any PHP variable that casts to an integer may be passed.
- */
-class Integer extends TypedData {
-
-  /**
-   * The data value.
-   *
-   * @var integer
-   */
-  protected $value;
-}
diff --git a/core/lib/Drupal/Core/TypedData/Type/Language.php b/core/lib/Drupal/Core/TypedData/Type/Language.php
deleted file mode 100644
index b910216..0000000
--- a/core/lib/Drupal/Core/TypedData/Type/Language.php
+++ /dev/null
@@ -1,83 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\Core\TypedData\Type\Language.
- */
-
-namespace Drupal\Core\TypedData\Type;
-
-use InvalidArgumentException;
-use Drupal\Core\Language\Language as LanguageObject;
-use Drupal\Core\TypedData\TypedData;
-
-/**
- * Defines the 'language' data type.
- *
- * The plain value of a language 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.
- *
- * 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.
- */
-class Language extends TypedData {
-
-  /**
-   * The language code of the language if no 'langcode source' is used.
-   *
-   * @var string
-   */
-  protected $langcode;
-
-  /**
-   * Overrides TypedData::getValue().
-   */
-  public function getValue() {
-    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));
-    }
-  }
-
-  /**
-   * Overrides TypedData::setValue().
-   *
-   * Both the langcode and the language object may be passed as value.
-   */
-  public function setValue($value, $notify = TRUE) {
-    // Support passing language objects.
-    if (is_object($value)) {
-      $value = $value->langcode;
-    }
-    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->langcode = $value;
-    }
-  }
-
-  /**
-   * Overrides TypedData::getString().
-   */
-  public function getString() {
-    $language = $this->getValue();
-    return $language ? $language->name : '';
-  }
-}
diff --git a/core/lib/Drupal/Core/TypedData/Type/Map.php b/core/lib/Drupal/Core/TypedData/Type/Map.php
deleted file mode 100644
index d19abe4..0000000
--- a/core/lib/Drupal/Core/TypedData/Type/Map.php
+++ /dev/null
@@ -1,244 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\Core\TypedData\Type\Map.
- */
-
-namespace Drupal\Core\TypedData\Type;
-
-use Drupal\Core\TypedData\TypedData;
-use Drupal\Core\TypedData\ComplexDataInterface;
-use Drupal\Core\TypedData\TypedDataInterface;
-
-/**
- * The "map" data type.
- *
- * The "map" data type represent a simple complex data type, e.g. for
- * representing associative arrays. It can also serve as base class for any
- * complex data type.
- *
- * By default there is no metadata for contained properties. Extending classes
- * may want to override Map::getPropertyDefinitions() to define it.
- */
-class Map extends TypedData implements \IteratorAggregate, ComplexDataInterface {
-
-  /**
-   * An array of values for the contained properties.
-   *
-   * @var array
-   */
-  protected $values = array();
-
-  /**
-   * The array of properties, each implementing the TypedDataInterface.
-   *
-   * @var array
-   */
-  protected $properties = array();
-
-  /**
-   * Implements \Drupal\Core\TypedData\ComplexDataInterface::getPropertyDefinitions().
-   */
-  public function getPropertyDefinitions() {
-    $definitions = array();
-    foreach ($this->values as $name => $value) {
-      $definitions[$name] = array(
-        'type' => 'any',
-      );
-    }
-    return $definitions;
-  }
-
-  /**
-   * Overrides \Drupal\Core\TypedData\TypedData::getValue().
-   */
-  public function getValue($include_computed = FALSE) {
-    // Update the values and return them.
-    foreach ($this->properties as $name => $property) {
-      $definition = $property->getDefinition();
-      if ($include_computed || empty($definition['computed'])) {
-        $value = $property->getValue();
-        // Only write NULL values if the whole map is not NULL.
-        if (isset($this->values) || isset($value)) {
-          $this->values[$name] = $value;
-        }
-      }
-    }
-    return $this->values;
-  }
-
-  /**
-   * Overrides \Drupal\Core\TypedData\TypedData::setValue().
-   *
-   * @param array|null $values
-   *   An array of property 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;
-
-    // Update any existing property objects.
-    foreach ($this->properties as $name => $property) {
-      $value = NULL;
-      if (isset($values[$name])) {
-        $value = $values[$name];
-      }
-      $property->setValue($value, FALSE);
-    }
-  }
-
-  /**
-   * Overrides \Drupal\Core\TypedData\TypedData::getString().
-   */
-  public function getString() {
-    $strings = array();
-    foreach ($this->getProperties() as $property) {
-      $strings[] = $property->getString();
-    }
-    // Remove any empty strings resulting from empty items.
-    return implode(', ', array_filter($strings, 'drupal_strlen'));
-  }
-
-  /**
-   * Implements \Drupal\Core\TypedData\ComplexDataInterface::get().
-   */
-  public function get($property_name) {
-    if (!isset($this->properties[$property_name])) {
-      $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] = \Drupal::typedData()->getPropertyInstance($this, $property_name, $value);
-    }
-    return $this->properties[$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);
-    }
-    else {
-      // Just set the plain value, which allows adding a new entry to the map.
-      $this->values[$property_name] = $value;
-    }
-  }
-
-  /**
-   * 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->get($name);
-      }
-    }
-    return $properties;
-  }
-
-  /**
-   * Implements \Drupal\Core\TypedData\ComplexDataInterface::getPropertyValues().
-   */
-  public function getPropertyValues() {
-    $values = array();
-    foreach ($this->getProperties() as $name => $property) {
-      $values[$name] = $property->getValue();
-    }
-    return $values;
-  }
-
-  /**
-   * 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->properties as $property) {
-      $definition = $property->getDefinition();
-      if (empty($definition['computed']) && $property->getValue() !== NULL) {
-        return FALSE;
-      }
-    }
-    if (isset($this->values)) {
-      foreach ($this->values as $name => $value) {
-        if (isset($value) && !isset($this->properties[$name])) {
-          return FALSE;
-        }
-      }
-    }
-    return TRUE;
-  }
-
-  /**
-   * Magic method: Implements a deep clone.
-   */
-  public function __clone() {
-    foreach ($this->properties as $name => $property) {
-      $this->properties[$name] = clone $property;
-      $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);
-    }
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function applyDefaultValue($notify = TRUE) {
-    // Apply the default value of all properties.
-    foreach ($this->getProperties() as $property) {
-      $property->applyDefaultValue(FALSE);
-    }
-    return $this;
-  }
-}
diff --git a/core/lib/Drupal/Core/TypedData/Type/String.php b/core/lib/Drupal/Core/TypedData/Type/String.php
deleted file mode 100644
index a9d096f..0000000
--- a/core/lib/Drupal/Core/TypedData/Type/String.php
+++ /dev/null
@@ -1,26 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\Core\TypedData\Type\String.
- */
-
-namespace Drupal\Core\TypedData\Type;
-
-use Drupal\Core\TypedData\TypedData;
-
-/**
- * The string data type.
- *
- * The plain value of a string is a regular PHP string. For setting the value
- * any PHP variable that casts to a string may be passed.
- */
-class String extends TypedData {
-
-  /**
-   * The data value.
-   *
-   * @var string
-   */
-  protected $value;
-}
diff --git a/core/lib/Drupal/Core/TypedData/Type/Uri.php b/core/lib/Drupal/Core/TypedData/Type/Uri.php
deleted file mode 100644
index 791dec9..0000000
--- a/core/lib/Drupal/Core/TypedData/Type/Uri.php
+++ /dev/null
@@ -1,25 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\Core\TypedData\Type\Uri.
- */
-
-namespace Drupal\Core\TypedData\Type;
-
-use Drupal\Core\TypedData\TypedData;
-
-/**
- * The URI data type.
- *
- * The plain value of a URI is an absolute URI represented as PHP string.
- */
-class Uri extends TypedData {
-
-  /**
-   * The data value.
-   *
-   * @var string
-   */
-  protected $value;
-}
diff --git a/core/lib/Drupal/Core/TypedData/TypedDataFactory.php b/core/lib/Drupal/Core/TypedData/TypedDataFactory.php
index ef67cf2..7c37225 100644
--- a/core/lib/Drupal/Core/TypedData/TypedDataFactory.php
+++ b/core/lib/Drupal/Core/TypedData/TypedDataFactory.php
@@ -46,7 +46,7 @@ public function createInstance($plugin_id, array $configuration, $name = NULL, $
 
     // Allow per-data definition overrides of the used classes, i.e. take over
     // classes specified in the data definition.
-    $key = empty($configuration['list']) ? 'class' : 'list class';
+    $key = empty($configuration['list']) ? 'class' : 'list_class';
     if (isset($configuration[$key])) {
       $class = $configuration[$key];
     }
diff --git a/core/lib/Drupal/Core/TypedData/TypedDataManager.php b/core/lib/Drupal/Core/TypedData/TypedDataManager.php
index c0f81b9..9364db3 100644
--- a/core/lib/Drupal/Core/TypedData/TypedDataManager.php
+++ b/core/lib/Drupal/Core/TypedData/TypedDataManager.php
@@ -11,8 +11,8 @@
 use Drupal\Component\Plugin\Discovery\ProcessDecorator;
 use Drupal\Component\Plugin\Discovery\DerivativeDiscoveryDecorator;
 use Drupal\Component\Plugin\PluginManagerBase;
+use Drupal\Core\Plugin\Discovery\AnnotatedClassDiscovery;
 use Drupal\Core\Plugin\Discovery\CacheDecorator;
-use Drupal\Core\Plugin\Discovery\HookDiscovery;
 use Drupal\Core\TypedData\Validation\MetadataFactory;
 use Drupal\Core\Validation\ConstraintManager;
 use Drupal\Core\Validation\DrupalTranslator;
@@ -46,7 +46,7 @@ class TypedDataManager extends PluginManagerBase {
    * @var array
    */
   protected $defaults = array(
-    'list class' => '\Drupal\Core\TypedData\ItemList',
+    'list_class' => '\Drupal\Core\TypedData\ItemList',
   );
 
   /**
@@ -56,8 +56,12 @@ class TypedDataManager extends PluginManagerBase {
    */
   protected $prototypes = array();
 
-  public function __construct() {
-    $this->discovery = new HookDiscovery('data_type_info');
+  public function __construct(\Traversable $namespaces) {
+    $annotation_namespaces = array(
+      'Drupal\Core\TypedData\Annotation' => DRUPAL_ROOT . '/core/lib',
+    );
+
+    $this->discovery = new AnnotatedClassDiscovery('DataType', $namespaces, $annotation_namespaces, 'Drupal\Core\TypedData\Annotation\DataType');
     $this->discovery = new DerivativeDiscoveryDecorator($this->discovery);
     $this->discovery = new ProcessDecorator($this->discovery, array($this, 'processDefinition'));
     $this->discovery = new CacheDecorator($this->discovery, 'typed_data:types');
@@ -104,13 +108,13 @@ public function createInstance($plugin_id, array $configuration, $name = NULL, $
    *   - class: If set and 'list' is FALSE, the class to use for creating the
    *     typed data object; otherwise the default class of the data type will be
    *     used.
-   *   - list class: If set and 'list' is TRUE, the class to use for creating
+   *   - list_class: If set and 'list' is TRUE, the class to use for creating
    *     the typed data object; otherwise the default list class of the data
    *     type will be used.
    *   - settings: An array of settings, as required by the used 'class'. See
    *     the documentation of the class for supported or required settings.
-   *   - list settings: An array of settings as required by the used
-   *     'list class'. See the documentation of the list class for support or
+   *   - list_settings: An array of settings as required by the used
+   *     'list_class'. See the documentation of the list class for support or
    *     required settings.
    *   - constraints: An array of validation constraints. See
    *     \Drupal\Core\TypedData\TypedDataManager::getConstraints() for details.
@@ -349,12 +353,16 @@ public function getConstraints($definition) {
 
     $type_definition = $this->getDefinition($definition['type']);
     // Auto-generate a constraint for the primitive type if we have a mapping.
-    if (isset($type_definition['primitive type'])) {
-      $constraints[] = $validation_manager->create('PrimitiveType', array('type' => $type_definition['primitive type']));
+    if (isset($type_definition['primitive_type'])) {
+      $constraints[] = $validation_manager->create('PrimitiveType', array('type' => $type_definition['primitive_type']));
     }
     // Add in constraints specified by the data type.
     if (isset($type_definition['constraints'])) {
       foreach ($type_definition['constraints'] as $name => $options) {
+        // Annotations do not support empty arrays.
+        if ($options === TRUE) {
+          $options = array();
+        }
         $constraints[] = $validation_manager->create($name, $options);
       }
     }
diff --git a/core/modules/comment/lib/Drupal/comment/FieldNewItem.php b/core/modules/comment/lib/Drupal/comment/FieldNewItem.php
index 73fabe5..3e23ae7 100644
--- a/core/modules/comment/lib/Drupal/comment/FieldNewItem.php
+++ b/core/modules/comment/lib/Drupal/comment/FieldNewItem.php
@@ -7,7 +7,7 @@
 
 namespace Drupal\comment;
 
-use Drupal\Core\Entity\Field\Type\IntegerItem;
+use Drupal\Core\Entity\Plugin\DataType\IntegerItem;
 
 /**
  * The field item for the 'new' field.
diff --git a/core/modules/email/email.module b/core/modules/email/email.module
index 2d24c39..6afbdeb 100644
--- a/core/modules/email/email.module
+++ b/core/modules/email/email.module
@@ -28,7 +28,7 @@ function email_field_info() {
       'description' => t('This field stores an e-mail address in the database.'),
       'default_widget' => 'email_default',
       'default_formatter' => 'email_mailto',
-      'class' => 'Drupal\Core\Entity\Field\Type\EmailItem',
+      'class' => 'Drupal\Core\Entity\Plugin\DataType\EmailItem',
     ),
   );
 }
diff --git a/core/modules/entity_reference/entity_reference.module b/core/modules/entity_reference/entity_reference.module
index 6940452..572836e 100644
--- a/core/modules/entity_reference/entity_reference.module
+++ b/core/modules/entity_reference/entity_reference.module
@@ -39,7 +39,7 @@ function entity_reference_field_info() {
  *
  * Set the "target_type" property definition for entity reference fields.
  *
- * @see \Drupal\Core\Entity\Field\Type\EntityReferenceItem::getPropertyDefinitions()
+ * @see \Drupal\Core\Entity\Plugin\DataType\EntityReferenceItem::getPropertyDefinitions()
  *
  * @param array $info
  *   The property info array as returned by hook_entity_field_info().
diff --git a/core/modules/entity_reference/lib/Drupal/entity_reference/Type/ConfigurableEntityReferenceItem.php b/core/modules/entity_reference/lib/Drupal/entity_reference/Type/ConfigurableEntityReferenceItem.php
index f02490d..287ab81 100644
--- a/core/modules/entity_reference/lib/Drupal/entity_reference/Type/ConfigurableEntityReferenceItem.php
+++ b/core/modules/entity_reference/lib/Drupal/entity_reference/Type/ConfigurableEntityReferenceItem.php
@@ -7,7 +7,7 @@
 
 namespace Drupal\entity_reference\Type;
 
-use Drupal\Core\Entity\Field\Type\EntityReferenceItem;
+use Drupal\Core\Entity\Plugin\DataType\EntityReferenceItem;
 use Drupal\field\Plugin\Type\FieldType\ConfigEntityReferenceItemBase;
 use Drupal\field\Plugin\Type\FieldType\ConfigFieldItemInterface;
 
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 4535159..12d8c64 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
@@ -7,7 +7,7 @@
 
 namespace Drupal\field\Plugin\Type\FieldType;
 
-use Drupal\Core\Entity\Field\Type\EntityReferenceItem;
+use Drupal\Core\Entity\Plugin\DataType\EntityReferenceItem;
 use Drupal\field\Plugin\Type\FieldType\ConfigFieldItemInterface;
 use Drupal\field\Plugin\Core\Entity\Field;
 
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 3134160..dfc4fba 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
@@ -8,7 +8,7 @@
 namespace Drupal\field\Plugin\Type\FieldType;
 
 use Drupal\Core\TypedData\TypedDataInterface;
-use Drupal\Core\Entity\Field\Type\Field;
+use Drupal\Core\Entity\Field\Field;
 use Drupal\field\Field as FieldAPI;
 
 /**
diff --git a/core/modules/hal/lib/Drupal/hal/Normalizer/EntityReferenceItemNormalizer.php b/core/modules/hal/lib/Drupal/hal/Normalizer/EntityReferenceItemNormalizer.php
index f3e67b5..7143654 100644
--- a/core/modules/hal/lib/Drupal/hal/Normalizer/EntityReferenceItemNormalizer.php
+++ b/core/modules/hal/lib/Drupal/hal/Normalizer/EntityReferenceItemNormalizer.php
@@ -19,7 +19,7 @@ class EntityReferenceItemNormalizer extends FieldItemNormalizer implements UuidR
    *
    * @var string
    */
-  protected $supportedInterfaceOrClass = 'Drupal\Core\Entity\Field\Type\EntityReferenceItem';
+  protected $supportedInterfaceOrClass = 'Drupal\Core\Entity\Plugin\DataType\EntityReferenceItem';
 
   /**
    * Implements \Symfony\Component\Serializer\Normalizer\NormalizerInterface::normalize()
diff --git a/core/modules/path/lib/Drupal/path/Plugin/DataType/PathItem.php b/core/modules/path/lib/Drupal/path/Plugin/DataType/PathItem.php
new file mode 100644
index 0000000..e72e3a7
--- /dev/null
+++ b/core/modules/path/lib/Drupal/path/Plugin/DataType/PathItem.php
@@ -0,0 +1,52 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\path\Plugin\DataType\PathItem.
+ */
+
+namespace Drupal\path\Plugin\DataType;
+
+use Drupal\Core\TypedData\Annotation\DataType;
+use Drupal\Core\Annotation\Translation;
+use Drupal\Core\Entity\Field\FieldItemBase;
+
+/**
+ * Defines the 'path_field' entity field item.
+ *
+ * @DataType(
+ *   id = "path_field",
+ *   label = @Translation("Path field item"),
+ *   description = @Translation("An entity field containing a path alias and related data."),
+ *   list_class = "\Drupal\Core\Entity\Field\Field"
+ * )
+ */
+class PathItem extends FieldItemBase {
+
+  /**
+   * Definitions of the contained properties.
+   *
+   * @see PathItem::getPropertyDefinitions()
+   *
+   * @var array
+   */
+  static $propertyDefinitions;
+
+  /**
+   * Implements \Drupal\Core\TypedData\ComplexDataInterface::getPropertyDefinitions().
+   */
+  public function getPropertyDefinitions() {
+    if (!isset(static::$propertyDefinitions)) {
+      static::$propertyDefinitions['alias'] = array(
+        'type' => 'string',
+        'label' => t('Path alias'),
+      );
+      static::$propertyDefinitions['pid'] = array(
+        'type' => 'integer',
+        'label' => t('Path id'),
+      );
+    }
+    return static::$propertyDefinitions;
+  }
+
+}
diff --git a/core/modules/path/lib/Drupal/path/Type/PathItem.php b/core/modules/path/lib/Drupal/path/Type/PathItem.php
deleted file mode 100644
index 9b8abd1..0000000
--- a/core/modules/path/lib/Drupal/path/Type/PathItem.php
+++ /dev/null
@@ -1,43 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\path\Type\PathItem.
- */
-
-namespace Drupal\path\Type;
-
-use Drupal\Core\Entity\Field\FieldItemBase;
-
-/**
- * Defines the 'path_field' entity field item.
- */
-class PathItem extends FieldItemBase {
-
-  /**
-   * Definitions of the contained properties.
-   *
-   * @see PathItem::getPropertyDefinitions()
-   *
-   * @var array
-   */
-  static $propertyDefinitions;
-
-  /**
-   * Implements \Drupal\Core\TypedData\ComplexDataInterface::getPropertyDefinitions().
-   */
-  public function getPropertyDefinitions() {
-    if (!isset(static::$propertyDefinitions)) {
-      static::$propertyDefinitions['alias'] = array(
-        'type' => 'string',
-        'label' => t('Path alias'),
-      );
-      static::$propertyDefinitions['pid'] = array(
-        'type' => 'integer',
-        'label' => t('Path id'),
-      );
-    }
-    return static::$propertyDefinitions;
-  }
-
-}
diff --git a/core/modules/path/path.module b/core/modules/path/path.module
index efc59a8..4cb0ddd 100644
--- a/core/modules/path/path.module
+++ b/core/modules/path/path.module
@@ -263,19 +263,6 @@ function path_form_taxonomy_term_form_alter(&$form, $form_state) {
 }
 
 /**
- * Implements hook_data_type_info().
- */
-function path_data_type_info() {
-  $info['path_field'] = array(
-    'label' => t('Path field item'),
-    'description' => t('An entity field containing a path alias and related data.'),
-    'class' => '\Drupal\path\Type\PathItem',
-    'list class' => '\Drupal\Core\Entity\Field\Type\Field',
-  );
-  return $info;
-}
-
-/**
  * Implements hook_entity_field_info().
  */
 function path_entity_field_info($entity_type) {
diff --git a/core/modules/system/system.api.php b/core/modules/system/system.api.php
index e9e69c5..febf298 100644
--- a/core/modules/system/system.api.php
+++ b/core/modules/system/system.api.php
@@ -132,57 +132,6 @@ function hook_cron() {
 }
 
 /**
- * Defines available data types for the typed data API.
- *
- * The typed data API allows modules to support any kind of data based upon
- * pre-defined primitive types and interfaces for complex data and lists.
- *
- * Defined data types may map to one of the pre-defined primitive types in
- * \Drupal\Core\TypedData\Primitive or may be complex data types, containing one
- * or more data properties. Typed data objects for complex data types have to
- * implement the \Drupal\Core\TypedData\ComplexDataInterface. Further interfaces
- * that may be implemented are:
- *  - \Drupal\Core\TypedData\AccessibleInterface
- *  - \Drupal\Core\TypedData\TranslatableInterface
- *
- * Furthermore, lists of data items are represented by objects implementing
- * the \Drupal\Core\TypedData\ListInterface. A list contains items of the same
- * data type, is ordered and may contain duplicates. The classed used for a list
- * of items of a certain type may be specified using the 'list class' key.
- *
- * @return array
- *   An associative array where the key is the data type name and the value is
- *   again an associative array. Supported keys are:
- *   - label: The human readable label of the data type.
- *   - class: The associated typed data class. Must implement the
- *     \Drupal\Core\TypedData\TypedDataInterface.
- *   - list class: (optional) A typed data class used for wrapping multiple
- *     data items of the type. Must implement the
- *     \Drupal\Core\TypedData\ListInterface. Defaults to
- *     \Drupal\Core\TypedData\ItemList;
- *   - primitive type: (optional) Maps the data type to one of the pre-defined
- *     primitive types in \Drupal\Core\TypedData\Primitive. If set, it must be
- *     a constant defined by \Drupal\Core\TypedData\Primitive such as
- *     \Drupal\Core\TypedData\Primitive::STRING.
- *   - constraints: An array of validation constraints for this type. See
- *     \Drupal\Core\TypedData\TypedDataManager::getConstraints() for details.
- *
- * @see \Drupal::typedData()
- * @see Drupal\Core\TypedData\TypedDataManager::create()
- * @see hook_data_type_info_alter()
- */
-function hook_data_type_info() {
-  return array(
-    'email' => array(
-      'label' => t('Email'),
-      'class' => '\Drupal\email\Type\Email',
-      'primitive type' => \Drupal\Core\TypedData\Primitive::STRING,
-      'constraints' => array('Email' => array()),
-    ),
-  );
-}
-
-/**
  * Alter available data types for typed data wrappers.
  *
  * @param array $data_types
diff --git a/core/modules/system/system.module b/core/modules/system/system.module
index 15aa52c..359b69c 100644
--- a/core/modules/system/system.module
+++ b/core/modules/system/system.module
@@ -2162,152 +2162,6 @@ function system_stream_wrappers() {
 }
 
 /**
- * Implements hook_data_type_info().
- */
-function system_data_type_info() {
-  return array(
-    'boolean' => array(
-      'label' => t('Boolean'),
-      'class' => '\Drupal\Core\TypedData\Type\Boolean',
-      'primitive type' => Primitive::BOOLEAN,
-    ),
-    'string' => array(
-      'label' => t('String'),
-      'class' => '\Drupal\Core\TypedData\Type\String',
-      'primitive type' => Primitive::STRING,
-    ),
-    'integer' => array(
-      'label' => t('Integer'),
-      'class' => '\Drupal\Core\TypedData\Type\Integer',
-      'primitive type' => Primitive::INTEGER,
-    ),
-    'float' => array(
-      'label' => t('Float'),
-      'class' => '\Drupal\Core\TypedData\Type\Float',
-      'primitive type' => Primitive::FLOAT,
-    ),
-    'date' => array(
-      'label' => t('Date'),
-      'class' => '\Drupal\Core\TypedData\Type\Date',
-      'primitive type' => Primitive::DATE,
-    ),
-    'duration' => array(
-      'label' => t('Duration'),
-      'class' => '\Drupal\Core\TypedData\Type\Duration',
-      'primitive type' => Primitive::DURATION,
-    ),
-    'uri' => array(
-      'label' => t('URI'),
-      'class' => '\Drupal\Core\TypedData\Type\Uri',
-      'primitive type' => Primitive::URI,
-    ),
-    'email' => array(
-      'label' => t('Email'),
-      'class' => '\Drupal\Core\TypedData\Type\Email',
-      'primitive type' => Primitive::STRING,
-      'constraints' => array('Email' => array()),
-    ),
-    'binary' => array(
-      'label' => t('Binary'),
-      'class' => '\Drupal\Core\TypedData\Type\Binary',
-      'primitive type' => Primitive::BINARY,
-    ),
-    'map' => array(
-      'label' => t('Map'),
-      'class' =>  '\Drupal\Core\TypedData\Type\Map',
-    ),
-    'any' => array(
-      'label' => t('Any data'),
-      'class' =>  '\Drupal\Core\TypedData\Type\Any',
-    ),
-    'language' => array(
-      'label' => t('Language'),
-      'description' => t('A language object.'),
-      'class' => '\Drupal\Core\TypedData\Type\Language',
-    ),
-    'entity' => array(
-      'label' => t('Entity'),
-      'description' => t('All kind of entities, e.g. nodes, comments or users.'),
-      'class' => '\Drupal\Core\Entity\Field\Type\EntityWrapper',
-    ),
-    'entity_translation' => array(
-      'label' => t('Entity translation'),
-      'description' => t('A translation of an entity'),
-      'class' => '\Drupal\Core\Entity\Field\Type\EntityTranslation',
-    ),
-    'boolean_field' => array(
-      'label' => t('Boolean field item'),
-      'description' => t('An entity field containing a boolean value.'),
-      'class' => '\Drupal\Core\Entity\Field\Type\BooleanItem',
-      'list class' => '\Drupal\Core\Entity\Field\Type\Field',
-    ),
-    'string_field' => array(
-      'label' => t('String field item'),
-      'description' => t('An entity field containing a string value.'),
-      'class' => '\Drupal\Core\Entity\Field\Type\StringItem',
-      'list class' => '\Drupal\Core\Entity\Field\Type\Field',
-    ),
-    'email_field' => array(
-      'label' => t('E-mail field item'),
-      'description' => t('An entity field containing an e-mail value.'),
-      'class' => '\Drupal\Core\Entity\Field\Type\EmailItem',
-      'list class' => '\Drupal\Core\Entity\Field\Type\Field',
-    ),
-    'integer_field' => array(
-      'label' => t('Integer field item'),
-      'description' => t('An entity field containing an integer value.'),
-      'class' => '\Drupal\Core\Entity\Field\Type\IntegerItem',
-      'list class' => '\Drupal\Core\Entity\Field\Type\Field',
-    ),
-    'date_field' => array(
-      'label' => t('Date field item'),
-      'description' => t('An entity field containing a date value.'),
-      'class' => '\Drupal\Core\Entity\Field\Type\DateItem',
-      'list class' => '\Drupal\Core\Entity\Field\Type\Field',
-    ),
-    'language_field' => array(
-      'label' => t('Language field item'),
-      'description' => t('An entity field referencing a language.'),
-      'class' => '\Drupal\Core\Entity\Field\Type\LanguageItem',
-      'list class' => '\Drupal\Core\Entity\Field\Type\Field',
-      'constraints' => array(
-        'ComplexData' => array(
-          'value' => array('Length' => array('max' => 12)),
-        ),
-      ),
-    ),
-    'entity_reference_field' => array(
-      'label' => t('Entity reference field item'),
-      'description' => t('An entity field containing an entity reference.'),
-      'class' => '\Drupal\Core\Entity\Field\Type\EntityReferenceItem',
-      'list class' => '\Drupal\Core\Entity\Field\Type\Field',
-    ),
-    'uri_field' => array(
-      'label' => t('URI field item'),
-      'description' => t('An entity field containing a URI'),
-      'class' => '\Drupal\Core\Entity\Field\Type\UriItem',
-      'list class' => '\Drupal\Core\Entity\Field\Type\Field',
-    ),
-    'uuid_field' => array(
-      'label' => t('UUID field item'),
-      'description' => t('An entity field containing a UUID.'),
-      'class' => '\Drupal\Core\Entity\Field\Type\UuidItem',
-      'list class' => '\Drupal\Core\Entity\Field\Type\Field',
-      'constraints' => array(
-        'ComplexData' => array(
-          'value' => array('Length' => array('max' => 128)),
-        ),
-      ),
-    ),
-    // Expose each field type as a data type. We add one single entry, which
-    // will be expanded through plugin derivatives.
-    'field_item' => array(
-      'derivative' => '\Drupal\Core\Entity\Plugin\DataType\FieldDataTypeDerivative',
-    ),
-  );
-}
-
-/**
  * Menu item access callback - only enabled themes can be accessed.
  */
 function _system_themes_access($theme) {
diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/Type/TaxonomyTermReferenceItem.php b/core/modules/taxonomy/lib/Drupal/taxonomy/Type/TaxonomyTermReferenceItem.php
index 082ed5d..9396327 100644
--- a/core/modules/taxonomy/lib/Drupal/taxonomy/Type/TaxonomyTermReferenceItem.php
+++ b/core/modules/taxonomy/lib/Drupal/taxonomy/Type/TaxonomyTermReferenceItem.php
@@ -7,7 +7,7 @@
 
 namespace Drupal\taxonomy\Type;
 
-use Drupal\Core\Entity\Field\Type\EntityReferenceItem;
+use Drupal\Core\Entity\Plugin\DataType\EntityReferenceItem;
 use Drupal\field\Plugin\Type\FieldType\ConfigEntityReferenceItemBase;
 
 /**
