diff --git a/core/lib/Drupal/Core/Entity/EntityManager.php b/core/lib/Drupal/Core/Entity/EntityManager.php
index 67e5690..d4b5bbb 100644
--- a/core/lib/Drupal/Core/Entity/EntityManager.php
+++ b/core/lib/Drupal/Core/Entity/EntityManager.php
@@ -10,6 +10,7 @@
 use Drupal\Component\Plugin\PluginManagerBase;
 use Drupal\Component\Plugin\Factory\DefaultFactory;
 use Drupal\Component\Utility\NestedArray;
+use Drupal\Core\Entity\Field\FieldDefinition;
 use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\Language\LanguageManager;
 use Drupal\Core\Language\Language;
@@ -455,15 +456,8 @@ public function getAdminRouteInfo($entity_type, $bundle) {
    *   is passed, no bundle-specific fields are included. Defaults to NULL.
    *
    * @return array
-   *   An array of field definitions of entity fields, keyed by field
-   *   name. In addition to the typed data definition keys as described at
-   *   \Drupal\Core\TypedData\TypedDataManager::create() the following keys are
-   *   supported:
-   *   - queryable: Whether the field is queryable via QueryInterface.
-   *     Defaults to TRUE if 'computed' is FALSE or not set, to FALSE otherwise.
-   *   - translatable: Whether the field is translatable. Defaults to FALSE.
-   *   - configurable: A boolean indicating whether the field is configurable
-   *     via field.module. Defaults to FALSE.
+   *   An array of entity field definitions, keyed by field name. See
+   *   \Drupal\Core\Entity\Field\FieldDefinitionInterface.
    *
    * @see \Drupal\Core\TypedData\TypedDataManager::create()
    * @see \Drupal\Core\Entity\EntityManager::getFieldDefinitionsByConstraints()
@@ -476,6 +470,7 @@ public function getFieldDefinitions($entity_type, $bundle = NULL) {
         $this->entityFieldInfo[$entity_type] = $cache->data;
       }
       else {
+        // @todo: Refactor to allow for per-bundle overrides.
         $class = $this->factory->getPluginClass($entity_type, $this->getDefinition($entity_type));
         $this->entityFieldInfo[$entity_type] = array(
           'definitions' => $class::baseFieldDefinitions($entity_type),
@@ -495,12 +490,16 @@ public function getFieldDefinitions($entity_type, $bundle = NULL) {
         $hooks = array('entity_field_info', $entity_type . '_field_info');
         $this->moduleHandler->alter($hooks, $this->entityFieldInfo[$entity_type], $entity_type);
 
-        // Enforce fields to be multiple by default.
-        foreach ($this->entityFieldInfo[$entity_type]['definitions'] as &$definition) {
-          $definition['list'] = TRUE;
+        // Enforce field definitions to be objects.
+        foreach ($this->entityFieldInfo[$entity_type]['definitions'] as $field_name => &$definition) {
+          if (is_array($definition)) {
+            $definition = FieldDefinition::createFromOldStyleDefinition($field_name, $definition);
+          }
         }
-        foreach ($this->entityFieldInfo[$entity_type]['optional'] as &$definition) {
-          $definition['list'] = TRUE;
+        foreach ($this->entityFieldInfo[$entity_type]['optional'] as $field_name => &$definition) {
+          if (is_array($definition)) {
+            $definition = FieldDefinition::createFromOldStyleDefinition($field_name, $definition);
+          }
         }
         $this->cache->set($cid, $this->entityFieldInfo[$entity_type], CacheBackendInterface::CACHE_PERMANENT, array('entity_info' => TRUE, 'entity_field_info' => TRUE));
       }
diff --git a/core/lib/Drupal/Core/Entity/Field/FieldDefinition.php b/core/lib/Drupal/Core/Entity/Field/FieldDefinition.php
index ef79967..42dcdc3 100644
--- a/core/lib/Drupal/Core/Entity/Field/FieldDefinition.php
+++ b/core/lib/Drupal/Core/Entity/Field/FieldDefinition.php
@@ -6,34 +6,20 @@
  */
 
 namespace Drupal\Core\Entity\Field;
+
 use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\TypedData\ListDefinition;
 
 /**
  * A class for defining entity fields.
  */
-class FieldDefinition implements FieldDefinitionInterface {
-
-  /**
-   * The array holding values for all definition keys.
-   *
-   * @var array
-   */
-  protected $definition = array();
-
-  /**
-   * Constructs a new FieldDefinition object.
-   *
-   * @param array $definition
-   *   (optional) If given, a definition represented as array.
-   */
-  public function __construct(array $definition = array()) {
-    $this->definition = $definition;
-  }
+class FieldDefinition extends ListDefinition implements FieldDefinitionInterface, \ArrayAccess {
 
   /**
    * {@inheritdoc}
    */
   public function getFieldName() {
+    // @todo: Should "name" be part of the data definition also?
     return $this->definition['field_name'];
   }
 
@@ -56,7 +42,7 @@ public function setFieldName($name) {
    */
   public function getFieldType() {
     // Cut of the leading field_item: prefix from 'field_item:FIELD_TYPE'.
-    $parts = explode(':', $this->definition['type']);
+    $parts = explode(':', $this->getItemDefinition()->getDataType());
     return $parts[1];
   }
 
@@ -70,43 +56,60 @@ public function getFieldType() {
    *   The object itself for chaining.
    */
   public function setFieldType($type) {
-    $this->definition['type'] = 'field_item:' . $type;
+    $this->getItemDefinition()->setDataType('field_item:' . $type);
     return $this;
   }
 
   /**
-   * Sets a field setting.
+   * {@inheritdoc}
+   */
+  public function getFieldSettings() {
+    return $this->getItemDefinition()->getSettings();
+  }
+
+  /**
+   * Sets field settings.
    *
-   * @param string $type
-   *   The field type to set.
+   * @param array $settings
+   *   The value to set.
    *
    * @return \Drupal\Core\Entity\Field\FieldDefinition
    *   The object itself for chaining.
    */
-  public function setFieldSetting($setting_name, $value) {
-    $this->definition['settings'][$setting_name] = $value;
-    return $this;
+  public function setFieldSettings(array $settings) {
+    return $this->getItemDefinition()->setSettings($settings);
   }
 
   /**
    * {@inheritdoc}
    */
-  public function getFieldSettings() {
-    return $this->definition['settings'];
+  public function getFieldSetting($setting_name) {
+    $settings = $this->getFieldSettings();
+    return isset($settings[$setting_name]) ? $settings[$setting_name] : NULL;
   }
 
   /**
-   * {@inheritdoc}
+   * Sets a field setting.
+   *
+   * @param string $setting_name
+   *   The field setting to set.
+   * @param mixed $value
+   *   The value to set.
+   *
+   * @return \Drupal\Core\Entity\Field\FieldDefinition
+   *   The object itself for chaining.
    */
-  public function getFieldSetting($setting_name) {
-    return isset($this->definition['settings'][$setting_name]) ? $this->definition['settings'][$setting_name] : NULL;
+  public function setFieldSetting($setting_name, $value) {
+    $settings = $this->getFieldSettings();
+    $settings[$setting_name] = $value;
+    return $this->setFieldSettings($settings);
   }
 
   /**
    * {@inheritdoc}
    */
   public function getFieldPropertyNames() {
-    return array_keys(\Drupal::typedData()->create($this->definition['type'])->getPropertyDefinitions());
+    return array_keys(\Drupal::typedData()->create($this->getItemDefinition())->getPropertyDefinitions());
   }
 
   /**
@@ -134,42 +137,28 @@ public function setTranslatable($translatable) {
    * {@inheritdoc}
    */
   public function getFieldLabel() {
-    return $this->definition['label'];
+    return $this->getLabel();
   }
 
   /**
-   * Sets the field label.
-   *
-   * @param string $label
-   *   The field label to set.
-   *
-   * @return \Drupal\Core\Entity\Field\FieldDefinition
-   *   The object itself for chaining.
+   * {@inheritdoc}
    */
   public function setFieldLabel($label) {
-    $this->definition['label'] = $label;
-    return $this;
+    return $this->setLabel($label);
   }
 
   /**
    * {@inheritdoc}
    */
   public function getFieldDescription() {
-    return $this->definition['description'];
+    return $this->getDescription();
   }
 
   /**
-   * Sets the field label.
-   *
-   * @param string $description
-   *   The field label to set.
-   *
-   * @return \Drupal\Core\Entity\Field\FieldDefinition
-   *   The object itself for chaining.
+   * {@inheritdoc}
    */
   public function setFieldDescription($description) {
-    $this->definition['description'] = $description;
-    return $this;
+    return $this->setDescription($description);
   }
 
   /**
@@ -184,21 +173,40 @@ public function getFieldCardinality() {
    * {@inheritdoc}
    */
   public function isFieldRequired() {
-    return !empty($this->definition['required']);
+    return $this->isRequired();
   }
 
   /**
    * Sets whether the field is required.
    *
-   * @param bool $required
-   *   TRUE if the field is required, FALSE otherwise.
+   * @param boolean $required
+   *   Whether the field is required.
    *
    * @return \Drupal\Core\Entity\Field\FieldDefinition
    *   The object itself for chaining.
    */
   public function setFieldRequired($required) {
-    $this->definition['required'] = $required;
-    return $this;
+    return $this->setRequired($required);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function isFieldQueryable() {
+    return isset($this->definition['queryable']) ? $this->definition['queryable'] : !$this->isComputed();
+  }
+
+  /**
+   * Sets whether the field is queryable.
+   *
+   * @param boolean $queryable
+   *   Whether the field is queryable.
+   *
+   * @return \Drupal\Core\Entity\Field\FieldDefinition
+   *   The object itself for chaining.
+   */
+  public function setFieldQueryable($queryable) {
+    return $this->setRequired($queryable);
   }
 
   /**
@@ -213,7 +221,9 @@ public function setFieldRequired($required) {
    *   The object itself for chaining.
    */
   public function setPropertyConstraints($name, array $constraints) {
-    $this->definition['item_definition']['constraints']['ComplexData'][$name] = $constraints;
+    $item_constraints = $this->getItemDefinition()->getConstraints();
+    $item_constraints['ComplexData'][$name] = $constraints;
+    $this->getItemDefinition()->setConstraints($item_constraints);
     return $this;
   }
 
@@ -231,4 +241,41 @@ public function getFieldDefaultValue(EntityInterface $entity) {
     return $this->getFieldSetting('default_value');
   }
 
+  /**
+   * Allows creating field definition objects from old style definition arrays.
+   *
+   * @todo: Remove once no old-style definition arrays need to be supported.
+   */
+  public static function createFromOldStyleDefinition($field_name, array $definition) {
+    unset($definition['list']);
+
+    $list_definition = $definition;
+    $list_definition['type'] = 'entity_field';
+    unset($list_definition['constraints']);
+    unset($list_definition['settings']);
+
+    $new = new FieldDefinition($list_definition);
+    if (isset($definition['list_class'])) {
+      $new->setClass($definition['list_class']);
+    }
+    else {
+      $type_definition = \Drupal::typedData()->getDefinition($definition['type']);
+      if (isset($type_definition['list_class'])) {
+        $new->setClass($type_definition['list_class']);
+      }
+    }
+
+    // Take care of the item definition.
+    $new->setItemDefinition(new FieldDefinition($definition));
+    $new->setFieldName($field_name);
+    $new->setFieldSettings($definition['settings']);
+    if (isset($definition['constraints'])) {
+      $new->getItemDefinition()->setConstraints($definition['constraints']);
+    }
+    if (isset($definition['class'])) {
+      $new->getItemDefinition()->setClass($definition['class']);
+    }
+    return $new;
+  }
+
 }
diff --git a/core/lib/Drupal/Core/Entity/Field/FieldDefinitionInterface.php b/core/lib/Drupal/Core/Entity/Field/FieldDefinitionInterface.php
index b8dc354..c2bc4ce 100644
--- a/core/lib/Drupal/Core/Entity/Field/FieldDefinitionInterface.php
+++ b/core/lib/Drupal/Core/Entity/Field/FieldDefinitionInterface.php
@@ -13,9 +13,10 @@
  * Defines an interface for entity field definitions.
  *
  * An entity field is a data object that holds the values of a particular field
- * for a particular entity (see \Drupal\Core\Entity\Field\FieldItemListInterface). For
- * example, $node_1->body and $node_2->body contain different data and therefore
- * are different field objects.
+ * for a particular entity (see
+ * \Drupal\Core\Entity\Field\FieldItemListInterface). For example, $node_1->body
+ * and $node_2->body contain different data and therefore are different field
+ * objects.
  *
  * In contrast, an entity field *definition* is an object that returns
  * information *about* a field (e.g., its type and settings) rather than its
@@ -36,10 +37,9 @@
  *
  * However, entity base fields, such as $node->title, are not managed by
  * field.module and its "field_entity"/"field_instance" configuration entities.
- * Therefore, their definitions are provided by different objects that implement
- * this interface.
- * @todo That is still in progress: https://drupal.org/node/1949932. Update this
- *   documentation with details when that's implemented.
+ * Therefore, their definitions are provided by different objects based on the
+ * class \Drupal\Core\Entity\Field\FieldDefinition, which implements this
+ * interface as well.
  *
  * Field definitions may fully define a concrete data object (e.g.,
  * $node_1->body), or may provide a best-guess definition for a data object that
@@ -50,6 +50,8 @@
  * abstractly, and present Views configuration options to the administrator
  * based on that abstract definition, even though that abstract definition can
  * differ from the concrete definition of any particular node's body field.
+ *
+ * @todo Extends this from DataDefinitionInterface.
  */
 interface FieldDefinitionInterface {
 
@@ -129,6 +131,13 @@ public function isFieldTranslatable();
   public function isFieldConfigurable();
 
   /**
+   * Determines whether the field is queryable via QueryInterface.
+   *
+   * @return bool
+   */
+  public function isFieldQueryable();
+
+  /**
    * Returns the human-readable label for the field.
    *
    * @return string
diff --git a/core/lib/Drupal/Core/Entity/Field/FieldItemBase.php b/core/lib/Drupal/Core/Entity/Field/FieldItemBase.php
index 15744c0..d459c49 100644
--- a/core/lib/Drupal/Core/Entity/Field/FieldItemBase.php
+++ b/core/lib/Drupal/Core/Entity/Field/FieldItemBase.php
@@ -8,6 +8,8 @@
 namespace Drupal\Core\Entity\Field;
 
 use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\TypedData\DataDefinition;
+use Drupal\Core\TypedData\DataDefinitionInterface;
 use Drupal\Core\TypedData\Plugin\DataType\Map;
 use Drupal\Core\TypedData\TypedDataInterface;
 use Drupal\user;
@@ -23,9 +25,16 @@
 abstract class FieldItemBase extends Map implements FieldItemInterface {
 
   /**
+   * The field's definition.
+   *
+   * @var \Drupal\Core\Entity\Field\FieldDefinitionInterface
+   */
+  protected $definition;
+
+  /**
    * Overrides \Drupal\Core\TypedData\TypedData::__construct().
    */
-  public function __construct(array $definition, $name = NULL, TypedDataInterface $parent = NULL) {
+  public function __construct($definition, $name = NULL, TypedDataInterface $parent = NULL) {
     parent::__construct($definition, $name, $parent);
     // Initialize computed properties by default, such that they get cloned
     // with the whole item.
diff --git a/core/lib/Drupal/Core/Entity/Field/FieldItemList.php b/core/lib/Drupal/Core/Entity/Field/FieldItemList.php
index 4b4e1eb..cf4e3aa 100644
--- a/core/lib/Drupal/Core/Entity/Field/FieldItemList.php
+++ b/core/lib/Drupal/Core/Entity/Field/FieldItemList.php
@@ -10,7 +10,7 @@
 use Drupal\Core\Entity\Field\FieldItemListInterface;
 use Drupal\Core\Session\AccountInterface;
 use Drupal\Core\TypedData\TypedDataInterface;
-use Drupal\Core\TypedData\ItemList;
+use Drupal\Core\TypedData\Plugin\DataType\ItemList;
 use Drupal\Core\Language\Language;
 
 /**
@@ -45,7 +45,7 @@ class FieldItemList extends ItemList implements FieldItemListInterface {
   /**
    * Overrides TypedData::__construct().
    */
-  public function __construct(array $definition, $name = NULL, TypedDataInterface $parent = NULL) {
+  public function __construct($definition, $name = NULL, TypedDataInterface $parent = NULL) {
     parent::__construct($definition, $name, $parent);
     $this->definition['field_name'] = $name;
     // Always initialize one empty item as most times a value for at least one
@@ -109,7 +109,7 @@ public function getValue($include_computed = FALSE) {
   }
 
   /**
-   * Overrides \Drupal\Core\TypedData\ItemList::setValue().
+   * Overrides \Drupal\Core\TypedData\Plugin\DataType\ItemList::setValue().
    */
   public function setValue($values, $notify = TRUE) {
     if (!isset($values) || $values === array()) {
diff --git a/core/lib/Drupal/Core/Entity/Plugin/DataType/FieldItemList.php b/core/lib/Drupal/Core/Entity/Plugin/DataType/FieldItemList.php
new file mode 100644
index 0000000..9a8225b
--- /dev/null
+++ b/core/lib/Drupal/Core/Entity/Plugin/DataType/FieldItemList.php
@@ -0,0 +1,26 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Entity\Plugin\DataType\FieldItemList.
+ */
+
+namespace Drupal\Core\Entity\Plugin\DataType;
+
+use Drupal\Core\TypedData\Annotation\DataType;
+use Drupal\Core\Annotation\Translation;
+
+/**
+ * Defines a data type plugin for entity fields, i.e. the list of field items.
+ *
+ * @todo: Move the whole implementation to this place.
+ *
+ * @DataType(
+ *   id = "entity_field",
+ *   label = @Translation("Entity field"),
+ *   class = "\Drupal\Core\Entity\Field\Field"
+ * )
+ */
+class FieldItemList extends \Drupal\Core\Entity\Field\FieldItemList {
+
+}
diff --git a/core/lib/Drupal/Core/TypedData/Annotation/DataType.php b/core/lib/Drupal/Core/TypedData/Annotation/DataType.php
index c0569ab..e28952d 100644
--- a/core/lib/Drupal/Core/TypedData/Annotation/DataType.php
+++ b/core/lib/Drupal/Core/TypedData/Annotation/DataType.php
@@ -62,14 +62,6 @@ class DataType extends Plugin {
   public $description;
 
   /**
-   * The typed data class used for wrapping multiple data items of the type.
-   * Must implement the \Drupal\Core\TypedData\ListInterface.
-   *
-   * @var string
-   */
-  public $list_class = '\Drupal\Core\TypedData\ItemList';
-
-  /**
    * The pre-defined primitive type that this data type maps to.
    *
    * If set, it must be a constant defined by \Drupal\Core\TypedData\Primitive
diff --git a/core/lib/Drupal/Core/TypedData/DataDefinition.php b/core/lib/Drupal/Core/TypedData/DataDefinition.php
new file mode 100644
index 0000000..316e06a
--- /dev/null
+++ b/core/lib/Drupal/Core/TypedData/DataDefinition.php
@@ -0,0 +1,302 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\TypedData\DataDefinition.
+ */
+
+namespace Drupal\Core\TypedData;
+
+/**
+ * A class for defining data based on defined data types.
+ */
+class DataDefinition implements DataDefinitionInterface, \ArrayAccess {
+
+  /**
+   * The array holding values for all definition keys.
+   *
+   * @var array
+   */
+  protected $definition = array();
+
+  /**
+   * Constructs a new data definition object.
+   *
+   * @param array $definition
+   *   (optional) If given, a data definition represented as array.
+   */
+  public function __construct(array $definition = array()) {
+    $this->definition = $definition;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getDataType() {
+    return $this->definition['type'];
+  }
+
+  /**
+   * Sets the data type.
+   *
+   * @param string $type
+   *   The data type to set.
+   *
+   * @return \Drupal\Core\TypedData\DataDefinition
+   *   The object itself for chaining.
+   */
+  public function setDataType($type) {
+    $this->definition['type'] = $type;
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getLabel() {
+    return isset($this->definition['label']) ? $this->definition['label'] : NULL;
+  }
+
+  /**
+   * Sets the human-readable label.
+   *
+   * @param string $label
+   *   The label to set.
+   *
+   * @return \Drupal\Core\TypedData\DataDefinition
+   *   The object itself for chaining.
+   */
+  public function setLabel($label) {
+    $this->definition['label'] = $label;
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getDescription() {
+    return isset($this->definition['description']) ? $this->definition['description'] : NULL;
+  }
+
+  /**
+   * Sets the human-readable description.
+   *
+   * @param string $description
+   *   The description to set.
+   *
+   * @return \Drupal\Core\TypedData\DataDefinition
+   *   The object itself for chaining.
+   */
+  public function setDescription($description) {
+    $this->definition['description'] = $description;
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function isList() {
+    return $this instanceof ListDefinitionInterface;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function isReadOnly() {
+    if (!isset($this->definition['read-only'])) {
+      // Default to read-only if the data value is computed.
+      return $this->isComputed();
+    }
+    return $this->definition['read-only'];
+  }
+
+  /**
+   * Sets whether the data is read-only.
+   *
+   * @param boolean $read-only
+   *   Whether the data is read-only.
+   *
+   * @return \Drupal\Core\TypedData\DataDefinition
+   *   The object itself for chaining.
+   */
+  public function setReadOnly($read_only) {
+    $this->definition['read-only'] = $read_only;
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function isComputed() {
+    return !empty($this->definition['computed']);
+  }
+
+  /**
+   * Sets whether the data is computed.
+   *
+   * @param boolean $computed
+   *   Whether the data is computed.
+   *
+   * @return \Drupal\Core\TypedData\DataDefinition
+   *   The object itself for chaining.
+   */
+  public function setComputed($computed) {
+    $this->definition['computed'] = $computed;
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function isRequired() {
+    return !empty($this->definition['required']);
+  }
+
+  /**
+   * Sets whether the data is required.
+   *
+   * @param boolean $required
+   *   Whether the data is required.
+   *
+   * @return \Drupal\Core\TypedData\DataDefinition
+   *   The object itself for chaining.
+   */
+  public function setRequired($required) {
+    $this->definition['required'] = $required;
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getClass() {
+    return isset($this->definition['class']) ? $this->definition['class'] : NULL;
+  }
+
+  /**
+   * Sets the class used for creating the typed data object.
+   *
+   * @param string|null $class
+   *   The class to use.
+   *
+   * @return \Drupal\Core\TypedData\DataDefinition
+   *   The object itself for chaining.
+   */
+  public function setClass($class) {
+    $this->definition['class'] = $class;
+    return $this;
+  }
+
+  /**
+   * Returns the array of settings, as required by the used class.
+   *
+   * See the documentation of the class for supported or required settings.
+   *
+   * @return array
+   *   The array of settings.
+   */
+  public function getSettings() {
+    return isset($this->definition['settings']) ? $this->definition['settings'] : array();
+  }
+
+  /**
+   * Sets the array of settings, as required by the used class.
+   *
+   * @param array $settings
+   *   The array of settings.
+   *
+   * @return \Drupal\Core\TypedData\DataDefinition
+   *   The object itself for chaining.
+   */
+  public function setSettings(array $settings) {
+    $this->definition['settings'] = $settings;
+    return $this;
+  }
+
+  /**
+   * Returns an array of validation constraints.
+   *
+   * See \Drupal\Core\TypedData\TypedDataManager::getConstraints() for details.
+   *
+   * @return array
+   *   Array of constraints, each being an instance of
+   *   \Symfony\Component\Validator\Constraint.
+   */
+  public function getConstraints() {
+    return isset($this->definition['constraints']) ? $this->definition['constraints'] : array();
+  }
+
+  /**
+   * Sets the array of validation constraints.
+   *
+   * See \Drupal\Core\TypedData\TypedDataManager::getConstraints() for details.
+   *
+   * @param array $constraints
+   *   The array of constraints.
+   *
+   * @return \Drupal\Core\TypedData\DataDefinition
+   *   The object itself for chaining.
+   */
+  public function setConstraints(array $constraints) {
+    $this->definition['constraints'] = $constraints;
+    return $this;
+  }
+
+  /**
+   * Adds a validation constraint.
+   *
+   * See \Drupal\Core\TypedData\TypedDataManager::getConstraints() for details.
+   *
+   * @param string $constraint_name
+   *   The name of the constraint to add, i.e. its plugin id.
+   * @param array|null $options
+   *   The constraint options as required by the constraint plugin, or NULL.
+   *
+   * @return \Drupal\Core\TypedData\DataDefinition
+   *   The object itself for chaining.
+   */
+  public function addConstraint($constraint_name, $options = NULL) {
+    $this->definition['constraints'][$constraint_name] = $options;
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function offsetExists($offset) {
+    return array_key_exists($offset, $this->definition);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function &offsetGet($offset) {
+    if (!isset($this->definition[$offset])) {
+      $this->definition[$offset] = NULL;
+    }
+    return $this->definition[$offset];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function offsetSet($offset, $value) {
+    $this->definition[$offset] = $value;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function offsetUnset($offset) {
+    unset($this->definition[$offset]);
+  }
+
+  /**
+   * Returns all definition values as array.
+   *
+   * @return array
+   */
+  public function toArray() {
+    return $this->definition;
+  }
+}
diff --git a/core/lib/Drupal/Core/TypedData/DataDefinitionInterface.php b/core/lib/Drupal/Core/TypedData/DataDefinitionInterface.php
new file mode 100644
index 0000000..d866d15
--- /dev/null
+++ b/core/lib/Drupal/Core/TypedData/DataDefinitionInterface.php
@@ -0,0 +1,115 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\TypedData\DataDefinitionInterface.
+ */
+
+namespace Drupal\Core\TypedData;
+
+/**
+ * Interface for data definitions.
+ *
+ * Data definitions are used to describe data based upon available data types.
+ * For example, a plugin could describe its parameters using data definitions
+ * in order to specify what kind of data is required for it.
+ *
+ * @see \Drupal\Core\TypedData\DataDefinition
+ */
+interface DataDefinitionInterface {
+
+  /**
+   * Returns the data type of the data.
+   *
+   * @return string
+   *   The data type.
+   */
+  public function getDataType();
+
+  /**
+   * Returns a human readable label.
+   *
+   * @return string
+   *   The label.
+   */
+  public function getLabel();
+
+  /**
+   * Returns a human readable description.
+   *
+   * @return string
+   *   The description.
+   */
+  public function getDescription();
+
+  /**
+   * Returns whether the data is multi-valued, i.e. a list of data items.
+   *
+   * This is equivalent to checking whether the data definition implements the
+   * \Drupal\Core\TypedData\ListDefinitionInterface interface.
+   *
+   * @return boolean
+   *   Whether the data is multi-valued.
+   */
+  public function isList();
+
+  /**
+   * Determines whether the data is read-only.
+   *
+   * @return boolean
+   *   Whether the data is read-only.
+   */
+  public function isReadOnly();
+
+  /**
+   * Determines whether the data value is computed.
+   *
+   * For example, data could be computed depending on some other values.
+   *
+   * @return boolean
+   *   Whether the data value is computed.
+   */
+  public function isComputed();
+
+  /**
+   * Determines whether a data value is required.
+   *
+   * For required data a non-NULL value is mandatory.
+   *
+   * @return boolean
+   *   Whether a data value is required.
+   */
+  public function isRequired();
+
+  /**
+   * Returns the class used for creating the typed data object.
+   *
+   * If not specified, the default class of the data type will be used.
+   *
+   * @return string|null
+   *   The class used for creating the typed data object.
+   */
+  public function getClass();
+
+  /**
+   * Returns the array of settings, as required by the used class.
+   *
+   * See the documentation of the class for supported or required settings.
+   *
+   * @return array
+   *   The array of settings.
+   */
+  public function getSettings();
+
+  /**
+   * Returns an array of validation constraints.
+   *
+   * See \Drupal\Core\TypedData\TypedDataManager::getConstraints() for details.
+   *
+   * @return array
+   *   Array of constraints, each being an instance of
+   *   \Symfony\Component\Validator\Constraint.
+   */
+  public function getConstraints();
+
+}
diff --git a/core/lib/Drupal/Core/TypedData/ItemList.php b/core/lib/Drupal/Core/TypedData/ItemList.php
deleted file mode 100644
index 9b39e83..0000000
--- a/core/lib/Drupal/Core/TypedData/ItemList.php
+++ /dev/null
@@ -1,224 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\Core\TypedData\List.
- */
-
-namespace Drupal\Core\TypedData;
-
-/**
- * A generic list class.
- *
- * This class can serve as list for any type of items.
- * Note: The class cannot be called "List" as list is a reserved PHP keyword.
- */
-class ItemList extends TypedData implements \IteratorAggregate, ListInterface {
-
-  /**
-   * Numerically indexed array items.
-   *
-   * @var array
-   */
-  protected $list = array();
-
-  /**
-   * Overrides \Drupal\Core\TypedData\TypedData::getValue().
-   */
-  public function getValue() {
-    if (isset($this->list)) {
-      $values = array();
-      foreach ($this->list as $delta => $item) {
-        $values[$delta] = $item->getValue();
-      }
-      return $values;
-    }
-  }
-
-  /**
-   * Overrides \Drupal\Core\TypedData\TypedData::setValue().
-   *
-   * @param array|null $values
-   *   An array of values of the field items, or NULL to unset the field.
-   */
-  public function setValue($values, $notify = TRUE) {
-    if (!isset($values) || $values === array()) {
-      $this->list = $values;
-    }
-    else {
-      if (!is_array($values)) {
-        throw new \InvalidArgumentException('Cannot set a list with a non-array value.');
-      }
-
-      // 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);
-        }
-      }
-    }
-    // Notify the parent of any changes.
-    if ($notify && isset($this->parent)) {
-      $this->parent->onChange($this->name);
-    }
-  }
-
-  /**
-   * Overrides \Drupal\Core\TypedData\TypedData::getString().
-   */
-  public function getString() {
-    $strings = array();
-    if (isset($this->list)) {
-      foreach ($this->list as $item) {
-        $strings[] = $item->getString();
-      }
-      // Remove any empty strings resulting from empty items.
-      return implode(', ', array_filter($strings, 'drupal_strlen'));
-    }
-  }
-
-  /**
-   * Overrides \Drupal\Core\TypedData\TypedData::getConstraints().
-   */
-  public function getConstraints() {
-    // Apply the constraints to the list items only.
-    return array();
-  }
-
-  /**
-   * Implements \ArrayAccess::offsetExists().
-   */
-  public function offsetExists($offset) {
-    return isset($this->list) && array_key_exists($offset, $this->list) && $this->offsetGet($offset)->getValue() !== NULL;
-  }
-
-  /**
-   * Implements \ArrayAccess::offsetUnset().
-   */
-  public function offsetUnset($offset) {
-    if (isset($this->list)) {
-      unset($this->list[$offset]);
-    }
-  }
-
-  /**
-   * Implements \ArrayAccess::offsetGet().
-   */
-  public function offsetGet($offset) {
-    if (!is_numeric($offset)) {
-      throw new \InvalidArgumentException('Unable to get a value with a non-numeric delta in a list.');
-    }
-    // Allow getting not yet existing items as well.
-    // @todo: Maybe add a public createItem() method in addition?
-    elseif (!isset($this->list[$offset])) {
-      $this->list[$offset] = $this->createItem($offset);
-    }
-    return $this->list[$offset];
-  }
-
-  /**
-   * Helper for creating a list item object.
-   *
-   * @return \Drupal\Core\TypedData\TypedDataInterface
-   */
-  protected function createItem($offset = 0, $value = NULL) {
-    return \Drupal::typedData()->getPropertyInstance($this, $offset, $value);
-  }
-
-  /**
-   * Implements \Drupal\Core\TypedData\ListInterface::getItemDefinition().
-   */
-  public function getItemDefinition() {
-    return array('list' => FALSE) + $this->definition;
-  }
-
-  /**
-   * Implements \ArrayAccess::offsetSet().
-   */
-  public function offsetSet($offset, $value) {
-    if (!isset($offset)) {
-      // The [] operator has been used so point at a new entry.
-      $offset = $this->list ? max(array_keys($this->list)) + 1 : 0;
-    }
-    if (is_numeric($offset)) {
-      // Support setting values via typed data objects.
-      if ($value instanceof TypedDataInterface) {
-        $value = $value->getValue();
-      }
-      $this->offsetGet($offset)->setValue($value);
-    }
-    else {
-      throw new \InvalidArgumentException('Unable to set a value with a non-numeric delta in a list.');
-    }
-  }
-
-  /**
-   * Implements \IteratorAggregate::getIterator().
-   */
-  public function getIterator() {
-    if (isset($this->list)) {
-      return new \ArrayIterator($this->list);
-    }
-    return new \ArrayIterator(array());
-  }
-
-  /**
-   * Implements \Countable::count().
-   */
-  public function count() {
-    return isset($this->list) ? count($this->list) : 0;
-  }
-
-  /**
-   * Implements \Drupal\Core\TypedData\ListInterface::isEmpty().
-   */
-  public function isEmpty() {
-    if (isset($this->list)) {
-      foreach ($this->list as $item) {
-        if ($item instanceof ComplexDataInterface || $item instanceof ListInterface) {
-          if (!$item->isEmpty()) {
-            return FALSE;
-          }
-        }
-        // Other items are treated as empty if they have no value only.
-        elseif ($item->getValue() !== NULL) {
-          return FALSE;
-        }
-      }
-    }
-    return TRUE;
-  }
-
-  /**
-   * Implements \Drupal\Core\TypedData\ListInterface::onChange().
-   */
-  public function onChange($delta) {
-    // Notify the parent of changes.
-    if (isset($this->parent)) {
-      $this->parent->onChange($this->name);
-    }
-  }
-
-  /**
-   * Magic method: Implements a deep clone.
-   */
-  public function __clone() {
-    if (isset($this->list)) {
-      foreach ($this->list as $delta => $item) {
-        $this->list[$delta] = clone $item;
-        $this->list[$delta]->setContext($delta, $this);
-      }
-    }
-  }
-}
diff --git a/core/lib/Drupal/Core/TypedData/ListDefinition.php b/core/lib/Drupal/Core/TypedData/ListDefinition.php
new file mode 100644
index 0000000..fc6b557
--- /dev/null
+++ b/core/lib/Drupal/Core/TypedData/ListDefinition.php
@@ -0,0 +1,44 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\TypedData\ListDefinition.
+ */
+
+namespace Drupal\Core\TypedData;
+
+/**
+ * A class for defining data based on defined data types.
+ */
+class ListDefinition extends DataDefinition implements ListDefinitionInterface {
+
+  /**
+   * The data definition of a list item.
+   *
+   * @var \Drupal\Core\TypedData\DataDefinitionInterface
+   */
+  protected $itemDefinition;
+
+  /**
+   * {@inheritdoc}
+   */
+  public function __construct(array $definition = array()) {
+    parent::__construct($definition);
+    $this->itemDefinition = new DataDefinition();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getItemDefinition() {
+    return $this->itemDefinition;
+  }
+
+  /**
+   * Sets the item definition.
+   */
+  public function setItemDefinition(DataDefinitionInterface $definition) {
+    $this->itemDefinition = $definition;
+    return $this;
+  }
+}
diff --git a/core/lib/Drupal/Core/TypedData/ListDefinitionInterface.php b/core/lib/Drupal/Core/TypedData/ListDefinitionInterface.php
new file mode 100644
index 0000000..0bf8aaf
--- /dev/null
+++ b/core/lib/Drupal/Core/TypedData/ListDefinitionInterface.php
@@ -0,0 +1,26 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\TypedData\DataDefinitionInterface.
+ */
+
+namespace Drupal\Core\TypedData;
+
+/**
+ * Interface for data definitions of lists.
+ *
+ * This interface is present on a data definition if it describes a list. The
+ * actual lists implement the \Drupal\Core\TypedData\ListInterface.
+ */
+interface ListDefinitionInterface extends DataDefinitionInterface {
+
+  /**
+   * Gets the data definition of an item of the list.
+   *
+   * @return \Drupal\Core\TypedData\DataDefinitionInterface
+   *   A data definition describing the list items.
+   */
+  public function getItemDefinition();
+
+}
diff --git a/core/lib/Drupal/Core/TypedData/Plugin/DataType/ItemList.php b/core/lib/Drupal/Core/TypedData/Plugin/DataType/ItemList.php
new file mode 100644
index 0000000..6e7b71e
--- /dev/null
+++ b/core/lib/Drupal/Core/TypedData/Plugin/DataType/ItemList.php
@@ -0,0 +1,238 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\TypedData\Plugin\DataType\ItemList.
+ */
+
+namespace Drupal\Core\TypedData\Plugin\DataType;
+
+use Drupal\Core\TypedData\Annotation\DataType;
+use Drupal\Core\Annotation\Translation;
+use Drupal\Core\TypedData\ListInterface;
+use Drupal\Core\TypedData\TypedData;
+
+/**
+ * A generic list class.
+ *
+ * This class can serve as list for any type of items.
+ * Note: The class cannot be called "List" as list is a reserved PHP keyword.
+ *
+ * @DataType(
+ *   id = "list",
+ *   label = @Translation("List of items")
+ * )
+ */
+class ItemList extends TypedData implements \IteratorAggregate, ListInterface {
+
+  /**
+   * Numerically indexed array items.
+   *
+   * @var array
+   */
+  protected $list = array();
+
+  /**
+   * Overrides \Drupal\Core\TypedData\TypedData::getValue().
+   */
+  public function getValue() {
+    if (isset($this->list)) {
+      $values = array();
+      foreach ($this->list as $delta => $item) {
+        $values[$delta] = $item->getValue();
+      }
+      return $values;
+    }
+  }
+
+  /**
+   * Overrides \Drupal\Core\TypedData\TypedData::setValue().
+   *
+   * @param array|null $values
+   *   An array of values of the field items, or NULL to unset the field.
+   */
+  public function setValue($values, $notify = TRUE) {
+    if (!isset($values) || $values === array()) {
+      $this->list = $values;
+    }
+    else {
+      if (!is_array($values)) {
+        throw new \InvalidArgumentException('Cannot set a list with a non-array value.');
+      }
+
+      // 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);
+        }
+      }
+    }
+    // Notify the parent of any changes.
+    if ($notify && isset($this->parent)) {
+      $this->parent->onChange($this->name);
+    }
+  }
+
+  /**
+   * Overrides \Drupal\Core\TypedData\TypedData::getString().
+   */
+  public function getString() {
+    $strings = array();
+    if (isset($this->list)) {
+      foreach ($this->list as $item) {
+        $strings[] = $item->getString();
+      }
+      // Remove any empty strings resulting from empty items.
+      return implode(', ', array_filter($strings, 'drupal_strlen'));
+    }
+  }
+
+  /**
+   * Overrides \Drupal\Core\TypedData\TypedData::getConstraints().
+   */
+  public function getConstraints() {
+    if (isset($this->definition['item_definition']) && isset($this->definition['constraints'])) {
+      return $this->definition['constraints'];
+    }
+    // BC: If no item definition is specified, we apply possibly specified
+    // constraints to the list items only.
+    return array();
+  }
+
+  /**
+   * Implements \ArrayAccess::offsetExists().
+   */
+  public function offsetExists($offset) {
+    return isset($this->list) && array_key_exists($offset, $this->list) && $this->offsetGet($offset)->getValue() !== NULL;
+  }
+
+  /**
+   * Implements \ArrayAccess::offsetUnset().
+   */
+  public function offsetUnset($offset) {
+    if (isset($this->list)) {
+      unset($this->list[$offset]);
+    }
+  }
+
+  /**
+   * Implements \ArrayAccess::offsetGet().
+   */
+  public function offsetGet($offset) {
+    if (!is_numeric($offset)) {
+      throw new \InvalidArgumentException('Unable to get a value with a non-numeric delta in a list.');
+    }
+    // Allow getting not yet existing items as well.
+    // @todo: Maybe add a public createItem() method in addition?
+    elseif (!isset($this->list[$offset])) {
+      $this->list[$offset] = $this->createItem($offset);
+    }
+    return $this->list[$offset];
+  }
+
+  /**
+   * Helper for creating a list item object.
+   *
+   * @return \Drupal\Core\TypedData\TypedDataInterface
+   */
+  protected function createItem($offset = 0, $value = NULL) {
+    return \Drupal::typedData()->getPropertyInstance($this, $offset, $value);
+  }
+
+  /**
+   * Implements \Drupal\Core\TypedData\ListInterface::getItemDefinition().
+   */
+  public function getItemDefinition() {
+    return $this->definition->getItemDefinition();
+  }
+
+  /**
+   * Implements \ArrayAccess::offsetSet().
+   */
+  public function offsetSet($offset, $value) {
+    if (!isset($offset)) {
+      // The [] operator has been used so point at a new entry.
+      $offset = $this->list ? max(array_keys($this->list)) + 1 : 0;
+    }
+    if (is_numeric($offset)) {
+      // Support setting values via typed data objects.
+      if ($value instanceof TypedDataInterface) {
+        $value = $value->getValue();
+      }
+      $this->offsetGet($offset)->setValue($value);
+    }
+    else {
+      throw new \InvalidArgumentException('Unable to set a value with a non-numeric delta in a list.');
+    }
+  }
+
+  /**
+   * Implements \IteratorAggregate::getIterator().
+   */
+  public function getIterator() {
+    if (isset($this->list)) {
+      return new \ArrayIterator($this->list);
+    }
+    return new \ArrayIterator(array());
+  }
+
+  /**
+   * Implements \Countable::count().
+   */
+  public function count() {
+    return isset($this->list) ? count($this->list) : 0;
+  }
+
+  /**
+   * Implements \Drupal\Core\TypedData\ListInterface::isEmpty().
+   */
+  public function isEmpty() {
+    if (isset($this->list)) {
+      foreach ($this->list as $item) {
+        if ($item instanceof ComplexDataInterface || $item instanceof ListInterface) {
+          if (!$item->isEmpty()) {
+            return FALSE;
+          }
+        }
+        // Other items are treated as empty if they have no value only.
+        elseif ($item->getValue() !== NULL) {
+          return FALSE;
+        }
+      }
+    }
+    return TRUE;
+  }
+
+  /**
+   * Implements \Drupal\Core\TypedData\ListInterface::onChange().
+   */
+  public function onChange($delta) {
+    // Notify the parent of changes.
+    if (isset($this->parent)) {
+      $this->parent->onChange($this->name);
+    }
+  }
+
+  /**
+   * Magic method: Implements a deep clone.
+   */
+  public function __clone() {
+    if (isset($this->list)) {
+      foreach ($this->list as $delta => $item) {
+        $this->list[$delta] = clone $item;
+        $this->list[$delta]->setContext($delta, $this);
+      }
+    }
+  }
+}
diff --git a/core/lib/Drupal/Core/TypedData/TypedData.php b/core/lib/Drupal/Core/TypedData/TypedData.php
index b97587b..8f8fb07 100644
--- a/core/lib/Drupal/Core/TypedData/TypedData.php
+++ b/core/lib/Drupal/Core/TypedData/TypedData.php
@@ -20,7 +20,7 @@
   /**
    * The data definition.
    *
-   * @var array
+   * @var \Drupal\Core\TypedData\DataDefinitionInterface
    */
   protected $definition;
 
@@ -41,7 +41,7 @@
   /**
    * Constructs a TypedData object given its definition and context.
    *
-   * @param array $definition
+   * @param \Drupal\Core\TypedData\DataDefinitionInterface $definition
    *   The data definition.
    * @param string $name
    *   (optional) The name of the created property, or NULL if it is the root
@@ -52,7 +52,7 @@
    *
    * @see Drupal\Core\TypedData\TypedDataManager::create()
    */
-  public function __construct(array $definition, $name = NULL, TypedDataInterface $parent = NULL) {
+  public function __construct($definition, $name = NULL, TypedDataInterface $parent = NULL) {
     $this->definition = $definition;
     $this->parent = $parent;
     $this->name = $name;
diff --git a/core/lib/Drupal/Core/TypedData/TypedDataInterface.php b/core/lib/Drupal/Core/TypedData/TypedDataInterface.php
index bbdf4ea..bef5a36 100644
--- a/core/lib/Drupal/Core/TypedData/TypedDataInterface.php
+++ b/core/lib/Drupal/Core/TypedData/TypedDataInterface.php
@@ -18,7 +18,9 @@
    * Gets the data definition.
    *
    * @return array
-   *   The data definition array.
+   *   The data definition represented as array.
+   *
+   * @see \Drupal\Core\TypedData\DataDefinition
    */
   public function getDefinition();
 
diff --git a/core/lib/Drupal/Core/TypedData/TypedDataManager.php b/core/lib/Drupal/Core/TypedData/TypedDataManager.php
index bbc0d7f..38d69e6 100644
--- a/core/lib/Drupal/Core/TypedData/TypedDataManager.php
+++ b/core/lib/Drupal/Core/TypedData/TypedDataManager.php
@@ -58,6 +58,7 @@ public function __construct(\Traversable $namespaces, CacheBackendInterface $cac
    *   The id of a plugin, i.e. the data type.
    * @param array $configuration
    *   The plugin configuration, i.e. the data definition.
+   *   //TODO: update docs
    * @param string $name
    *   (optional) If a property or list item is to be created, the name of the
    *   property or the delta of the list item.
@@ -69,7 +70,8 @@ public function __construct(\Traversable $namespaces, CacheBackendInterface $cac
    * @return \Drupal\Core\TypedData\TypedDataInterface
    *   The instantiated typed data object.
    */
-  public function createInstance($plugin_id, array $configuration, $name = NULL, $parent = NULL) {
+  public function createInstance($plugin_id, array $configuration) {
+    $data_definition = $configuration['data_definition'];
     $type_definition = $this->getDefinition($plugin_id);
 
     if (!isset($type_definition)) {
@@ -78,51 +80,21 @@ 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';
-    if (isset($configuration[$key])) {
-      $class = $configuration[$key];
-    }
-    elseif (isset($type_definition[$key])) {
-      $class = $type_definition[$key];
-    }
+    $class = $data_definition->getClass();
+    $class = isset($class) ? $class : $type_definition['class'];
 
     if (!isset($class)) {
       throw new PluginException(sprintf('The plugin (%s) did not specify an instance class.', $plugin_id));
     }
-    return new $class($configuration, $name, $parent);
+    return new $class($data_definition, $configuration['name'], $configuration['parent']);
   }
 
   /**
    * Creates a new typed data object instance.
    *
-   * @param array $definition
-   *   The data definition array with the following array keys and values:
-   *   - type: The data type of the data to wrap. Required.
-   *   - label: A human readable label.
-   *   - description: A human readable description.
-   *   - list: Whether the data is multi-valued, i.e. a list of data items.
-   *     Defaults to FALSE.
-   *   - computed: A boolean specifying whether the data value is computed by
-   *     the object, e.g. depending on some other values.
-   *   - read-only: A boolean specifying whether the data is read-only. Defaults
-   *     to TRUE for computed properties, to FALSE otherwise.
-   *   - 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
-   *     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
-   *     required settings.
-   *   - constraints: An array of validation constraints. See
-   *     \Drupal\Core\TypedData\TypedDataManager::getConstraints() for details.
-   *   - required: A boolean specifying whether a non-NULL value is mandatory.
-   *   Further keys may be supported in certain usages, e.g. for further keys
-   *   supported for entity field definitions see
-   *   \Drupal\Core\Entity\StorageControllerInterface::getPropertyDefinitions().
+   * @param \Drupal\Core\TypedData\DataDefinitionInterface $definition
+   *   The data definition of the typed data object. For backwards-compatibility
+   *   an array representation of the data definition may be passed also.
    * @param mixed $value
    *   (optional) The data value. If set, it has to match one of the supported
    *   data type format as documented for the data type classes.
@@ -147,14 +119,20 @@ public function createInstance($plugin_id, array $configuration, $name = NULL, $
    * @see \Drupal\Core\TypedData\Plugin\DataType\Date
    * @see \Drupal\Core\TypedData\Plugin\DataType\Uri
    * @see \Drupal\Core\TypedData\Plugin\DataType\Binary
-   * @see \Drupal\Core\Entity\Field\EntityWrapper
    */
-  public function create(array $definition, $value = NULL, $name = NULL, $parent = NULL) {
-    $wrapper = $this->createInstance($definition['type'], $definition, $name, $parent);
+  public function create($definition, $value = NULL, $name = NULL, $parent = NULL) {
+    if (is_array($definition)) {
+      $definition = new DataDefinition($definition);
+    }
+    $typed_data = $this->createInstance($definition->getDataType(), array(
+      'data_definition' => $definition,
+      'name' => $name,
+      'parent' => $parent,
+    ));
     if (isset($value)) {
-      $wrapper->setValue($value, FALSE);
+      $typed_data->setValue($value, FALSE);
     }
-    return $wrapper;
+    return $typed_data;
   }
 
   /**
@@ -336,7 +314,7 @@ public function getValidationConstraintManager() {
    *
    * @see \Drupal\Core\Validation\ConstraintManager
    *
-   * @param array $definition
+   * @param \Drupal\Core\TypedData\DataDefinitionInterface $definition
    *   A data definition array.
    *
    * @return array
diff --git a/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/ValidReferenceConstraintValidator.php b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/ValidReferenceConstraintValidator.php
index ba827e6..647188d 100644
--- a/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/ValidReferenceConstraintValidator.php
+++ b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/ValidReferenceConstraintValidator.php
@@ -19,6 +19,9 @@ class ValidReferenceConstraintValidator extends ConstraintValidator {
    * {@inheritdoc}
    */
   public function validate($value, Constraint $constraint) {
+    if (!isset($value)) {
+      return;
+    }
     $id = $value->get('target_id')->getValue();
     // '0' or NULL are considered valid empty references.
     if (empty($id)) {
diff --git a/core/modules/field/lib/Drupal/field/Entity/Field.php b/core/modules/field/lib/Drupal/field/Entity/Field.php
index 1b763b3..7d81cb8 100644
--- a/core/modules/field/lib/Drupal/field/Entity/Field.php
+++ b/core/modules/field/lib/Drupal/field/Entity/Field.php
@@ -698,6 +698,20 @@ public function hasData() {
   }
 
   /**
+   * {@inheritdoc}
+   */
+  public function isFieldQueryable() {
+    return TRUE;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function isFieldConfigurable() {
+    return TRUE;
+  }
+
+  /**
    * Implements the magic __sleep() method.
    *
    * Using the Serialize interface and serialize() / unserialize() methods
@@ -718,11 +732,4 @@ public function __wakeup() {
     $this->__construct($values);
   }
 
-  /**
-   * {@inheritdoc}
-   */
-  public function isFieldConfigurable() {
-    return TRUE;
-  }
-
 }
diff --git a/core/modules/field/lib/Drupal/field/Entity/FieldInstance.php b/core/modules/field/lib/Drupal/field/Entity/FieldInstance.php
index 412bae2..954b6b6 100644
--- a/core/modules/field/lib/Drupal/field/Entity/FieldInstance.php
+++ b/core/modules/field/lib/Drupal/field/Entity/FieldInstance.php
@@ -617,6 +617,13 @@ public function isFieldConfigurable() {
   /**
    * {@inheritdoc}
    */
+  public function isFieldQueryable() {
+    return TRUE;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   public function offsetExists($offset) {
     return (isset($this->{$offset}) || $offset == 'field_id' || $offset == 'field_name');
   }
diff --git a/core/modules/field/lib/Drupal/field/Plugin/Type/FieldType/ConfigFieldItemList.php b/core/modules/field/lib/Drupal/field/Plugin/Type/FieldType/ConfigFieldItemList.php
index 32bea80..2400e3d 100644
--- a/core/modules/field/lib/Drupal/field/Plugin/Type/FieldType/ConfigFieldItemList.php
+++ b/core/modules/field/lib/Drupal/field/Plugin/Type/FieldType/ConfigFieldItemList.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\field\Plugin\Type\FieldType;
 
+use Drupal\Core\TypedData\DataDefinitionInterface;
 use Drupal\Core\TypedData\TypedDataInterface;
 use Drupal\Core\Entity\Field\FieldItemList;
 use Drupal\field\Field as FieldAPI;
@@ -26,7 +27,7 @@ class ConfigFieldItemList extends FieldItemList implements ConfigFieldItemListIn
   /**
    * {@inheritdoc}
    */
-  public function __construct(array $definition, $name = NULL, TypedDataInterface $parent = NULL) {
+  public function __construct($definition, $name = NULL, TypedDataInterface $parent = NULL) {
     parent::__construct($definition, $name, $parent);
     if (isset($definition['instance'])) {
       $this->instance = $definition['instance'];
diff --git a/core/modules/locale/lib/Drupal/locale/LocaleTypedConfig.php b/core/modules/locale/lib/Drupal/locale/LocaleTypedConfig.php
index 5d6b200..4abf5d3 100644
--- a/core/modules/locale/lib/Drupal/locale/LocaleTypedConfig.php
+++ b/core/modules/locale/lib/Drupal/locale/LocaleTypedConfig.php
@@ -11,6 +11,7 @@
 use Drupal\Core\TypedData\ContextAwareInterface;
 use Drupal\Core\Config\Schema\Element;
 use Drupal\Core\Config\Schema\ArrayElement;
+use Drupal\Core\TypedData\DataDefinitionInterface;
 
 /**
  * Defines the locale configuration wrapper object.
@@ -41,7 +42,7 @@ class LocaleTypedConfig extends Element {
   /**
    * Constructs a configuration wrapper object.
    *
-   * @param array $definition
+   * @param \Drupal\Core\TypedData\DataDefinitionInterface $definition
    *   The data definition.
    * @param string $name
    *   The configuration object name.
@@ -50,7 +51,7 @@ class LocaleTypedConfig extends Element {
    * @param \Drupal\locale\LocaleConfigManager $localeConfig;
    *   The locale configuration manager object.
    */
-  public function __construct(array $definition, $name, $langcode, \Drupal\locale\LocaleConfigManager $localeConfig) {
+  public function __construct($definition, $name, $langcode, \Drupal\locale\LocaleConfigManager $localeConfig) {
     parent::__construct($definition, $name);
     $this->langcode = $langcode;
     $this->localeConfig = $localeConfig;
diff --git a/core/modules/text/lib/Drupal/text/TextProcessed.php b/core/modules/text/lib/Drupal/text/TextProcessed.php
index f3c65e2..aa20f8b 100644
--- a/core/modules/text/lib/Drupal/text/TextProcessed.php
+++ b/core/modules/text/lib/Drupal/text/TextProcessed.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\text;
 
+use Drupal\Core\TypedData\DataDefinitionInterface;
 use Drupal\Core\TypedData\TypedDataInterface;
 use Drupal\Core\TypedData\TypedData;
 use Drupal\Core\TypedData\ReadOnlyException;
@@ -29,7 +30,7 @@ class TextProcessed extends TypedData {
   /**
    * Overrides TypedData::__construct().
    */
-  public function __construct(array $definition, $name = NULL, TypedDataInterface $parent = NULL) {
+  public function __construct($definition, $name = NULL, TypedDataInterface $parent = NULL) {
     parent::__construct($definition, $name, $parent);
 
     if (!isset($definition['settings']['text source'])) {
