diff --git a/core/includes/entity.api.php b/core/includes/entity.api.php
index 2219d40..b718a4e 100644
--- a/core/includes/entity.api.php
+++ b/core/includes/entity.api.php
@@ -589,7 +589,7 @@ function hook_entity_operation_alter(array &$operations, \Drupal\Core\Entity\Ent
  * @param string $operation
  *   The operation to be performed. See
  *   \Drupal\Core\TypedData\AccessibleInterface::access() for possible values.
- * @param \Drupal\Core\Entity\Field\Field $field
+ * @param \Drupal\Core\Entity\Field\FieldItemList $field
  *   The entity field object on which the operation is to be performed.
  * @param \Drupal\Core\Session\AccountInterface $account
  *   The user account to check.
diff --git a/core/lib/Drupal/Core/Entity/EntityManager.php b/core/lib/Drupal/Core/Entity/EntityManager.php
index 4766a91..ce7fb6a 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\FieldInterface;
 use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\Language\LanguageManager;
 use Drupal\Core\Language\Language;
@@ -393,12 +394,12 @@ 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.
+        // Default to fields being multiple.
         foreach ($this->entityFieldInfo[$entity_type]['definitions'] as &$definition) {
-          $definition['list'] = TRUE;
+          $definition += array('list' => TRUE);
         }
         foreach ($this->entityFieldInfo[$entity_type]['optional'] as &$definition) {
-          $definition['list'] = TRUE;
+          $definition += array('list' => TRUE);
         }
         $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/EntityNG.php b/core/lib/Drupal/Core/Entity/EntityNG.php
index c3687a0..7b21adc 100644
--- a/core/lib/Drupal/Core/Entity/EntityNG.php
+++ b/core/lib/Drupal/Core/Entity/EntityNG.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\Core\Entity;
 
+use Drupal\Core\Entity\Field\FieldItemListInterface;
 use Drupal\Core\Language\Language;
 use Drupal\Core\TypedData\TypedDataInterface;
 use ArrayIterator;
@@ -475,7 +476,9 @@ public function updateOriginalValues() {
     foreach ($this->getPropertyDefinitions() as $name => $definition) {
       if (empty($definition['computed']) && !empty($this->fields[$name])) {
         foreach ($this->fields[$name] as $langcode => $field) {
-          $field->filterEmptyValues();
+          if ($field instanceof FieldItemListInterface) {
+            $field->filterEmptyValues();
+          }
           $this->values[$name][$langcode] = $field->getValue();
         }
       }
diff --git a/core/lib/Drupal/Core/Entity/Field/Field.php b/core/lib/Drupal/Core/Entity/Field/Field.php
deleted file mode 100644
index 3948ddf..0000000
--- a/core/lib/Drupal/Core/Entity/Field/Field.php
+++ /dev/null
@@ -1,296 +0,0 @@
-<?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/FieldAccessHelper.php b/core/lib/Drupal/Core/Entity/Field/FieldAccessHelper.php
new file mode 100644
index 0000000..10f00e3
--- /dev/null
+++ b/core/lib/Drupal/Core/Entity/Field/FieldAccessHelper.php
@@ -0,0 +1,83 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Entity\Field\FieldAccessHelper.
+ */
+
+namespace Drupal\Core\Entity\Field;
+use Drupal\Core\Extension\ModuleHandlerInterface;
+
+/**
+ * Helps checking field access.
+ *
+ * Field classes may leverage this helper for implementing default entity access
+ * logic. For being able to use the helper the
+ * class::defaultAccess($operation, $account) method has to be implemented.
+ */
+class FieldAccessHelper {
+
+  /**
+   * The module handler used.
+   *
+   * @var ModuleHandlerInterface
+   */
+  protected $moduleHandler;
+
+  /**
+   * Constructs a field access helper object.
+   * @param ModuleHandlerInterface $module_handler
+   */
+  public function __construct(ModuleHandlerInterface $module_handler) {
+    $this->moduleHandler = $module_handler;
+  }
+
+  /**
+   * Helps checking field access.
+   *
+   * @param \Drupal\Core\Entity\Field\FieldInterface $field
+   *   The field access is checked for.
+   * @param string $operation
+   *   (optional) The operation to be performed.
+   * @param \Drupal\Core\Session\AccountInterface $account
+   *   (optional) The user for which to check access, or NULL to check access
+   *   for the current user. Defaults to NULL.
+   *
+   * @return bool
+   *   TRUE if the given user has access for the given operation, FALSE
+   *   otherwise.
+   */
+  public function access(FieldInterface $field, $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 = $field->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 = $this->moduleHandler->getImplementations('entity_field_access');
+    foreach ($hook_implementations as $module) {
+      $grants = array_merge($grants, array($module => $this->moduleHandler->invoke($module, 'entity_field_access', $operation, $field, $account)));
+    }
+    // Also allow modules to alter the returned grants/denies.
+    $context = array(
+      'operation' => $operation,
+      'field' => $this,
+      'account' => $account,
+    );
+    $this->moduleHandler->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;
+  }
+}
\ No newline at end of file
diff --git a/core/lib/Drupal/Core/Entity/Field/FieldInterface.php b/core/lib/Drupal/Core/Entity/Field/FieldInterface.php
index c2dfbdb..bd00687 100644
--- a/core/lib/Drupal/Core/Entity/Field/FieldInterface.php
+++ b/core/lib/Drupal/Core/Entity/Field/FieldInterface.php
@@ -8,78 +8,26 @@
 namespace Drupal\Core\Entity\Field;
 
 use Drupal\Core\TypedData\AccessibleInterface;
-use Drupal\Core\TypedData\ListInterface;
+use Drupal\Core\TypedData\TypedDataInterface;
 
 /**
- * Interface for fields, being lists of field items.
+ * Interface for entity fields.
  *
- * This interface must be implemented by every entity field, whereas contained
- * field items must implement the FieldItemInterface.
- * Some methods of the fields are delegated to the first contained item, in
- * particular get() and set() as well as their magic equivalences.
+ * This interface must be implemented by every entity field, which may be any
+ * typed data object.
  *
- * Optionally, a typed data object implementing
- * Drupal\Core\TypedData\TypedDataInterface may be passed to
- * ArrayAccess::offsetSet() instead of a plain value.
- *
- * When implementing this interface which extends Traversable, make sure to list
- * IteratorAggregate or Iterator before this interface in the implements clause.
+ * Fields consisting of any number of field items based upon field type plugins
+ * should implement \Drupal\Core\Entity\Field\FieldItemListInterface.
  */
-interface FieldInterface extends ListInterface, AccessibleInterface {
-
-  /**
-   * Filters out empty field items and re-numbers the item deltas.
-   */
-  public function filterEmptyValues();
-
-  /**
-   * Gets a property object from the first field item.
-   *
-   * @see \Drupal\Core\Entity\Field\FieldItemInterface::get()
-   */
-  public function get($property_name);
-
-  /**
-   * Magic method: Gets a property value of to the first field item.
-   *
-   * @see \Drupal\Core\Entity\Field\FieldItemInterface::__get()
-   */
-  public function __get($property_name);
-
-  /**
-   * Magic method: Sets a property value of the first field item.
-   *
-   * @see \Drupal\Core\Entity\Field\FieldItemInterface::__set()
-   */
-  public function __set($property_name, $value);
-
-  /**
-   * Magic method: Determines whether a property of the first field item is set.
-   *
-   * @see \Drupal\Core\Entity\Field\FieldItemInterface::__isset()
-   */
-  public function __isset($property_name);
-
-  /**
-   * Magic method: Unsets a property of the first field item.
-   *
-   * @see \Drupal\Core\Entity\Field\FieldItemInterface::__unset()
-   */
-  public function __unset($property_name);
-
-  /**
-   * Gets the definition of a property of the first field item.
-   *
-   * @see \Drupal\Core\Entity\Field\FieldItemInterface::getPropertyDefinition()
-   */
-  public function getPropertyDefinition($name);
+interface FieldInterface extends TypedDataInterface, AccessibleInterface {
 
   /**
-   * Gets an array of property definitions of the first field item.
+   * Determines whether the field is empty.
    *
-   * @see \Drupal\Core\Entity\Field\FieldItemInterface::getPropertyDefinitions()
+   * @return boolean
+   *   TRUE if the data structure is empty, FALSE otherwise.
    */
-  public function getPropertyDefinitions();
+  public function isEmpty();
 
   /**
    * Defines custom presave behavior for field values.
diff --git a/core/lib/Drupal/Core/Entity/Field/FieldItemList.php b/core/lib/Drupal/Core/Entity/Field/FieldItemList.php
new file mode 100644
index 0000000..a74dc7d
--- /dev/null
+++ b/core/lib/Drupal/Core/Entity/Field/FieldItemList.php
@@ -0,0 +1,268 @@
+<?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 FieldItemList 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);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function access($operation = 'view', AccountInterface $account = NULL) {
+    // Leverage the field access helper to invoke entity field access hooks and
+    // default to defaultAccess().
+    return new FieldAccessHelper(\Drupal::moduleHandler());
+  }
+
+  /**
+   * Contains the default access logic of this field.
+   *
+   * See \Drupal\Core\TypedData\AccessibleInterface::access() for the parameter
+   * documentation. This method can be overridden by field 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/FieldItemListInterface.php b/core/lib/Drupal/Core/Entity/Field/FieldItemListInterface.php
new file mode 100644
index 0000000..95c9809
--- /dev/null
+++ b/core/lib/Drupal/Core/Entity/Field/FieldItemListInterface.php
@@ -0,0 +1,83 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Entity\Field\FieldItemListInterface.
+ */
+
+namespace Drupal\Core\Entity\Field;
+
+use Drupal\Core\TypedData\ListInterface;
+
+/**
+ * Interface for fields, being lists of field items.
+ *
+ * Fields implementing this interface consist of any number of field items, each
+ * implementing the FieldItemInterface. Some methods of the fields are delegated
+ * to the first contained item, in particular get() and set() as well as their
+ * magic equivalences.
+ *
+ * Optionally, a typed data object implementing
+ * Drupal\Core\TypedData\TypedDataInterface may be passed to
+ * ArrayAccess::offsetSet() instead of a plain value.
+ *
+ * When implementing this interface which extends Traversable, make sure to list
+ * IteratorAggregate or Iterator before this interface in the implements clause.
+ */
+interface FieldItemListInterface extends ListInterface, FieldInterface {
+
+  /**
+   * Filters out empty field items and re-numbers the item deltas.
+   */
+  public function filterEmptyValues();
+
+  /**
+   * Gets a property object from the first field item.
+   *
+   * @see \Drupal\Core\Entity\Field\FieldItemInterface::get()
+   */
+  public function get($property_name);
+
+  /**
+   * Magic method: Gets a property value of to the first field item.
+   *
+   * @see \Drupal\Core\Entity\Field\FieldItemInterface::__get()
+   */
+  public function __get($property_name);
+
+  /**
+   * Magic method: Sets a property value of the first field item.
+   *
+   * @see \Drupal\Core\Entity\Field\FieldItemInterface::__set()
+   */
+  public function __set($property_name, $value);
+
+  /**
+   * Magic method: Determines whether a property of the first field item is set.
+   *
+   * @see \Drupal\Core\Entity\Field\FieldItemInterface::__isset()
+   */
+  public function __isset($property_name);
+
+  /**
+   * Magic method: Unsets a property of the first field item.
+   *
+   * @see \Drupal\Core\Entity\Field\FieldItemInterface::__unset()
+   */
+  public function __unset($property_name);
+
+  /**
+   * Gets the definition of a property of the first field item.
+   *
+   * @see \Drupal\Core\Entity\Field\FieldItemInterface::getPropertyDefinition()
+   */
+  public function getPropertyDefinition($name);
+
+  /**
+   * Gets an array of property definitions of the first field item.
+   *
+   * @see \Drupal\Core\Entity\Field\FieldItemInterface::getPropertyDefinitions()
+   */
+  public function getPropertyDefinitions();
+
+}
diff --git a/core/lib/Drupal/Core/Entity/Plugin/DataType/BooleanItem.php b/core/lib/Drupal/Core/Entity/Plugin/DataType/BooleanItem.php
index 367cc74..31e3ec8 100644
--- a/core/lib/Drupal/Core/Entity/Plugin/DataType/BooleanItem.php
+++ b/core/lib/Drupal/Core/Entity/Plugin/DataType/BooleanItem.php
@@ -18,7 +18,7 @@
  *   id = "boolean_field",
  *   label = @Translation("Boolean field item"),
  *   description = @Translation("An entity field containing a boolean value."),
- *   list_class = "\Drupal\Core\Entity\Field\Field"
+ *   list_class = "\Drupal\Core\Entity\Field\FieldItemList"
  * )
  */
 class BooleanItem extends FieldItemBase {
diff --git a/core/lib/Drupal/Core/Entity/Plugin/DataType/DateItem.php b/core/lib/Drupal/Core/Entity/Plugin/DataType/DateItem.php
index 3fd9aa6..e6f462f 100644
--- a/core/lib/Drupal/Core/Entity/Plugin/DataType/DateItem.php
+++ b/core/lib/Drupal/Core/Entity/Plugin/DataType/DateItem.php
@@ -18,7 +18,7 @@
  *   id = "date_field",
  *   label = @Translation("Date field item"),
  *   description = @Translation("An entity field containing a date value."),
- *   list_class = "\Drupal\Core\Entity\Field\Field"
+ *   list_class = "\Drupal\Core\Entity\Field\FieldItemList"
  * )
  */
 class DateItem extends FieldItemBase {
diff --git a/core/lib/Drupal/Core/Entity/Plugin/DataType/EmailItem.php b/core/lib/Drupal/Core/Entity/Plugin/DataType/EmailItem.php
index b147976..b09a9fd 100644
--- a/core/lib/Drupal/Core/Entity/Plugin/DataType/EmailItem.php
+++ b/core/lib/Drupal/Core/Entity/Plugin/DataType/EmailItem.php
@@ -19,7 +19,7 @@
  *   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"
+ *   list_class = "\Drupal\Core\Entity\Field\FieldItemList"
  * )
  */
 class EmailItem extends LegacyConfigFieldItem {
diff --git a/core/lib/Drupal/Core/Entity/Plugin/DataType/EntityReferenceItem.php b/core/lib/Drupal/Core/Entity/Plugin/DataType/EntityReferenceItem.php
index 7f756ad..5c9e49b 100644
--- a/core/lib/Drupal/Core/Entity/Plugin/DataType/EntityReferenceItem.php
+++ b/core/lib/Drupal/Core/Entity/Plugin/DataType/EntityReferenceItem.php
@@ -22,7 +22,7 @@
  *   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"
+ *   list_class = "\Drupal\Core\Entity\Field\FieldItemList"
  * )
  */
 class EntityReferenceItem extends FieldItemBase {
diff --git a/core/lib/Drupal/Core/Entity/Plugin/DataType/FieldItem.php b/core/lib/Drupal/Core/Entity/Plugin/DataType/FieldItem.php
index 73309d9..54f8714 100644
--- a/core/lib/Drupal/Core/Entity/Plugin/DataType/FieldItem.php
+++ b/core/lib/Drupal/Core/Entity/Plugin/DataType/FieldItem.php
@@ -17,7 +17,7 @@
  * @DataType(
  *   id = "field_item",
  *   label = @Translation("Field item"),
- *   list_class = "\Drupal\Core\Entity\Field\Field",
+ *   list_class = "\Drupal\Core\Entity\Field\FieldItemList",
  *   derivative = "Drupal\Core\Entity\Plugin\DataType\FieldDataTypeDerivative"
  * )
  */
diff --git a/core/lib/Drupal/Core/Entity/Plugin/DataType/IntegerItem.php b/core/lib/Drupal/Core/Entity/Plugin/DataType/IntegerItem.php
index 4eb4db3..6bd8cf8 100644
--- a/core/lib/Drupal/Core/Entity/Plugin/DataType/IntegerItem.php
+++ b/core/lib/Drupal/Core/Entity/Plugin/DataType/IntegerItem.php
@@ -18,7 +18,7 @@
  *   id = "integer_field",
  *   label = @Translation("Integer field item"),
  *   description = @Translation("An entity field containing an integer value."),
- *   list_class = "\Drupal\Core\Entity\Field\Field"
+ *   list_class = "\Drupal\Core\Entity\Field\FieldItemList"
  * )
  */
 class IntegerItem extends FieldItemBase {
diff --git a/core/lib/Drupal/Core/Entity/Plugin/DataType/LanguageItem.php b/core/lib/Drupal/Core/Entity/Plugin/DataType/LanguageItem.php
index 5338556..3fd370f 100644
--- a/core/lib/Drupal/Core/Entity/Plugin/DataType/LanguageItem.php
+++ b/core/lib/Drupal/Core/Entity/Plugin/DataType/LanguageItem.php
@@ -19,7 +19,7 @@
  *   id = "language_field",
  *   label = @Translation("Language field item"),
  *   description = @Translation("An entity field referencing a language."),
- *   list_class = "\Drupal\Core\Entity\Field\Field",
+ *   list_class = "\Drupal\Core\Entity\Field\FieldItemList",
  *   constraints = {
  *     "ComplexData" = {
  *       "value" = {"Length" = {"max" = 12}}
diff --git a/core/lib/Drupal/Core/Entity/Plugin/DataType/StringItem.php b/core/lib/Drupal/Core/Entity/Plugin/DataType/StringItem.php
index 1f22d49..a243567 100644
--- a/core/lib/Drupal/Core/Entity/Plugin/DataType/StringItem.php
+++ b/core/lib/Drupal/Core/Entity/Plugin/DataType/StringItem.php
@@ -18,7 +18,7 @@
  *   id = "string_field",
  *   label = @Translation("String field item"),
  *   description = @Translation("An entity field containing a string value."),
- *   list_class = "\Drupal\Core\Entity\Field\Field"
+ *   list_class = "\Drupal\Core\Entity\Field\FieldItemList"
  * )
  */
 class StringItem extends FieldItemBase {
diff --git a/core/lib/Drupal/Core/Entity/Plugin/DataType/StringItemField.php b/core/lib/Drupal/Core/Entity/Plugin/DataType/StringItemField.php
new file mode 100644
index 0000000..364b263
--- /dev/null
+++ b/core/lib/Drupal/Core/Entity/Plugin/DataType/StringItemField.php
@@ -0,0 +1,49 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Entity\Plugin\DataType\SingleStringField.
+ */
+
+namespace Drupal\Core\Entity\Plugin\DataType;
+
+use Drupal\Core\Entity\Field\FieldAccessHelper;
+use Drupal\Core\Entity\Field\FieldInterface;
+use Drupal\Core\Session\AccountInterface;
+use Drupal\Core\TypedData\Annotation\DataType;
+use Drupal\Core\Annotation\Translation;
+use Drupal\Core\TypedData\Plugin\DataType\String;
+
+/**
+ * Defines a string item field, i.e. a field consisting of a single string item.
+ *
+ * @DataType(
+ *   id = "string_field_single",
+ *   label = @Translation("String field (single)"),
+ *   description = @Translation("An entity field being a single string value.")
+ * )
+ */
+class StringItemField extends StringItem implements FieldInterface {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function access($operation = 'view', AccountInterface $account = NULL) {
+    // Leverage the field access helper to invoke entity field access hooks and
+    // default to defaultAccess().
+    return new FieldAccessHelper(\Drupal::moduleHandler());
+  }
+
+  /**
+   * Contains the default access logic of this field.
+   *
+   * @return bool
+   *   TRUE if access to this field is allowed per default, FALSE otherwise.
+   *
+   * @see \Drupal\Core\Entity\Field\FieldAccessHelper
+   */
+  public function defaultAccess($operation = 'view', AccountInterface $account = NULL) {
+    // Grant access per default.
+    return TRUE;
+  }
+}
diff --git a/core/lib/Drupal/Core/Entity/Plugin/DataType/UriItem.php b/core/lib/Drupal/Core/Entity/Plugin/DataType/UriItem.php
index 263ec22..d9cd766 100644
--- a/core/lib/Drupal/Core/Entity/Plugin/DataType/UriItem.php
+++ b/core/lib/Drupal/Core/Entity/Plugin/DataType/UriItem.php
@@ -18,7 +18,7 @@
  *   id = "uri_field",
  *   label = @Translation("URI field item"),
  *   description = @Translation("An entity field containing a URI."),
- *   list_class = "\Drupal\Core\Entity\Field\Field"
+ *   list_class = "\Drupal\Core\Entity\Field\FieldItemList"
  * )
  */
 class UriItem extends FieldItemBase {
diff --git a/core/lib/Drupal/Core/Entity/Plugin/DataType/UuidItem.php b/core/lib/Drupal/Core/Entity/Plugin/DataType/UuidItem.php
index 737409d..011673c 100644
--- a/core/lib/Drupal/Core/Entity/Plugin/DataType/UuidItem.php
+++ b/core/lib/Drupal/Core/Entity/Plugin/DataType/UuidItem.php
@@ -20,7 +20,7 @@
  *   id = "uuid_field",
  *   label = @Translation("UUID field item"),
  *   description = @Translation("An entity field containing a UUID."),
- *   list_class = "\Drupal\Core\Entity\Field\Field",
+ *   list_class = "\Drupal\Core\Entity\Field\FieldItemList",
  *   constraints = {
  *     "ComplexData" = {
  *       "value" = {"Length" = {"max" = 128}}
diff --git a/core/lib/Drupal/Core/TypedData/AccessibleInterface.php b/core/lib/Drupal/Core/TypedData/AccessibleInterface.php
index 2676006..dac4ae0 100644
--- a/core/lib/Drupal/Core/TypedData/AccessibleInterface.php
+++ b/core/lib/Drupal/Core/TypedData/AccessibleInterface.php
@@ -24,15 +24,13 @@
    *   - update
    *   - delete
    *   Defaults to 'view'.
-   * @param Drupal\Core\Session\AccountInterface $account
+   * @param \Drupal\Core\Session\AccountInterface $account
    *   (optional) The user for which to check access, or NULL to check access
    *   for the current user. Defaults to NULL.
    *
    * @return bool
    *   TRUE if the given user has access for the given operation, FALSE
    *   otherwise.
-   *
-   * @todo Don't depend on module level code.
    */
   public function access($operation = 'view', AccountInterface $account = NULL);
 
diff --git a/core/modules/field/lib/Drupal/field/Plugin/Type/FieldType/ConfigField.php b/core/modules/field/lib/Drupal/field/Plugin/Type/FieldType/ConfigField.php
index dfc4fba..186baf4 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,13 +8,13 @@
 namespace Drupal\field\Plugin\Type\FieldType;
 
 use Drupal\Core\TypedData\TypedDataInterface;
-use Drupal\Core\Entity\Field\Field;
+use Drupal\Core\Entity\Field\FieldItemList;
 use Drupal\field\Field as FieldAPI;
 
 /**
  * Represents a configurable entity field.
  */
-class ConfigField extends Field implements ConfigFieldInterface {
+class ConfigField extends FieldItemList implements ConfigFieldInterface {
 
   /**
    * The Field instance definition.
diff --git a/core/modules/node/lib/Drupal/node/NodeStorageController.php b/core/modules/node/lib/Drupal/node/NodeStorageController.php
index 524036b..d4cb26d 100644
--- a/core/modules/node/lib/Drupal/node/NodeStorageController.php
+++ b/core/modules/node/lib/Drupal/node/NodeStorageController.php
@@ -154,7 +154,8 @@ public function baseFieldDefinitions() {
     $properties['title'] = array(
       'label' => t('Title'),
       'description' => t('The title of this node, always treated as non-markup plain text.'),
-      'type' => 'string_field',
+      'type' => 'string_field_single',
+      'list' => FALSE,
     );
     $properties['uid'] = array(
       'label' => t('User ID'),
diff --git a/core/modules/path/lib/Drupal/path/Plugin/DataType/PathItem.php b/core/modules/path/lib/Drupal/path/Plugin/DataType/PathItem.php
index e72e3a7..11059b5 100644
--- a/core/modules/path/lib/Drupal/path/Plugin/DataType/PathItem.php
+++ b/core/modules/path/lib/Drupal/path/Plugin/DataType/PathItem.php
@@ -18,7 +18,7 @@
  *   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"
+ *   list_class = "\Drupal\Core\Entity\Field\FieldItemList"
  * )
  */
 class PathItem extends FieldItemBase {
