diff --git a/core/lib/Drupal/Core/Entity/Field/Type/Field.php b/core/lib/Drupal/Core/Entity/Field/Type/Field.php
index af45ada..95a459d 100644
--- a/core/lib/Drupal/Core/Entity/Field/Type/Field.php
+++ b/core/lib/Drupal/Core/Entity/Field/Type/Field.php
@@ -57,6 +57,20 @@ public function filterEmptyValues() {
   }
 
   /**
+   * {@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) {
diff --git a/core/lib/Drupal/Core/TypedData/Type/Map.php b/core/lib/Drupal/Core/TypedData/Type/Map.php
index 43e3790..9d3fbbc 100644
--- a/core/lib/Drupal/Core/TypedData/Type/Map.php
+++ b/core/lib/Drupal/Core/TypedData/Type/Map.php
@@ -53,11 +53,11 @@ public function getPropertyDefinitions() {
   /**
    * Overrides \Drupal\Core\TypedData\TypedData::getValue().
    */
-  public function getValue() {
+  public function getValue($include_computed = FALSE) {
     // Update the values and return them.
     foreach ($this->properties as $name => $property) {
       $definition = $property->getDefinition();
-      if (empty($definition['computed'])) {
+      if ($include_computed || empty($definition['computed'])) {
         $value = $property->getValue();
         // Only write NULL values if the whole map is not NULL.
         if (isset($this->values) || isset($value)) {
diff --git a/core/modules/field/field.attach.inc b/core/modules/field/field.attach.inc
index 7965679..d589a6a 100644
--- a/core/modules/field/field.attach.inc
+++ b/core/modules/field/field.attach.inc
@@ -170,7 +170,79 @@ function field_invoke_method($method, $target_function, EntityInterface $entity,
     // called.
     $target = call_user_func($target_function, $instance);
 
-    if (method_exists($target, $method)) {
+    // @todo Note: If we want make the new API official asap and port existing
+    // widgets / formatters progressively, this should be the other way around:
+    // - Update FormatterInterface & WidgetInterface method signatures
+    //   impacted methods:
+    //   Formatters:
+    //     prepareView(), view(), viewElements()
+    //   Widgets:
+    //     form(), extractFormValues(), flagErrors()
+    // - rename all existing implementations to [method]BC()
+    // - start by checking if method_exists($target, $method), else the
+    //   widget / formatter hasn't been converted yet, fallback to calling the
+    //   old $methodBC.
+    $methodNG = $method . 'NG';
+    if (method_exists($target, $methodNG)) {
+      $field = $instance->getField();
+      $field_name = $field->id();
+
+      // Determine the list of languages to iterate on.
+      $available_langcodes = field_available_languages($entity_type, $field);
+      $langcodes = _field_language_suggestion($available_langcodes, $options['langcode'], $field_name);
+
+      foreach ($langcodes as $langcode) {
+        // @todo getTranslation() only works on NG entities. Remove the
+        // condition and the second code branch when all core entity types are
+        // converted.
+        if ($translation = $entity->getTranslation($langcode)) {
+          $items = $translation->get($field_name);
+          // @todo EntityNG / Multilingual snafu here.
+          // Without locale or any field translation enabled:
+          // - $langcode (returned by _field_language_suggestion() above) is 'und',
+          // - $items->getParent()->language()->langcode is 'en'.
+          // Currently Widget::form() (still BC) puts values in $form_state['value'][$field_name]['und'].
+          // So if extractFormValuesNG() wants to be able to find them, it cannot
+          // rely on $items only, it needs the same $langcode.
+          // Maybe this issue just goes away when Widget::form() gets "NG-ified"
+          // too, then both methods use the langcode they read from $items, no problem.
+          // For now, we pass $langode as an explicit param.
+          $result = $target->$methodNG($items, $langcode, $a, $b);
+        }
+        else {
+          // For BC entities, instanciate the NG item object manually.
+          $definitions = \Drupal::entityManager()->getStorageController($entity_type)->getFieldDefinitions(array(
+            'EntityType' => $entity_type,
+            'Bundle' => $entity->bundle(),
+          ));
+          $itemsBC = isset($entity->{$field_name}[$langcode]) ? $entity->{$field_name}[$langcode] : array();
+          // @todo Exception : this calls setValue(), tries to set the
+          // 'formatted' property. For now, this is worked around by
+          // commenting out the Exception in TextProcessed::setValue().
+          $items = \Drupal::typedData()->create($definitions[$field_name], $itemsBC, $field_name, $entity);
+          // @todo See above about $langcode.
+          $result = $target->$methodNG($items, $langcode, $a, $b);
+
+          // Put back the items values in the entity.
+          $itemsBC = $items->getValue(TRUE);
+          if ($itemsBC !== array() || isset($entity->{$field_name}[$langcode])) {
+            $entity->{$field_name}[$langcode] = $itemsBC;
+          }
+        }
+
+        if (isset($result)) {
+          // For methods with array results, we merge results together.
+          // For methods with scalar results, we collect results in an array.
+          if (is_array($result)) {
+            $return = array_merge($return, $result);
+          }
+          else {
+            $return[] = $result;
+          }
+        }
+      }
+    }
+    elseif (method_exists($target, $method)) {
       $field = field_info_field_by_id($instance['field_id']);
       $field_name = $field['field_name'];
 
@@ -256,6 +328,9 @@ function field_invoke_method_multiple($method, $target_function, array $entities
   $grouped_targets = array();
   $return = array();
 
+  $methodNG = $method . 'NG';
+  $NG = array();
+
   // Go through the entities and collect the instances on which the method
   // should be called.
   foreach ($entities as $entity) {
@@ -275,7 +350,26 @@ function field_invoke_method_multiple($method, $target_function, array $entities
         $grouped_targets[$instance_id] = call_user_func($target_function, $instance);
       }
 
-      if (method_exists($grouped_targets[$instance_id], $method)) {
+      if (method_exists($grouped_targets[$instance_id], $methodNG)) {
+        // Track that for this $înstance, the target uses an NG method, will be
+        // needed later on.
+        $NG[$instance_id] = TRUE;
+
+        // Add the instance to the list of instances to invoke the hook on.
+        if (!isset($instances[$instance_id])) {
+          $instances[$instance_id] = $instance;
+        }
+
+        // Unless a language code suggestion is provided we iterate on all the
+        // available language codes.
+        $available_langcodes = field_available_languages($entity_type, $instance->getField());
+        $langcode = !empty($options['langcode'][$id]) ? $options['langcode'][$id] : $options['langcode'];
+        $langcodes = _field_language_suggestion($available_langcodes, $langcode, $field_name);
+        foreach ($langcodes as $langcode) {
+          $grouped_items[$instance_id][$langcode][$id] = $entity->getTranslation($langcode)->get($field_name);
+        }
+      }
+      elseif (method_exists($grouped_targets[$instance_id], $method)) {
         // Add the instance to the list of instances to invoke the hook on.
         if (!isset($instances[$instance_id])) {
           $instances[$instance_id] = $instance;
@@ -304,30 +398,51 @@ function field_invoke_method_multiple($method, $target_function, array $entities
 
     // Iterate over all the field translations.
     foreach ($grouped_items[$instance_id] as $langcode => &$items) {
-      $entities = $grouped_entities[$instance_id][$langcode];
-      $results = $grouped_targets[$instance_id]->$method($entities, $langcode, $items, $a, $b);
+      if (isset($NG[$instance_id])) {
+        // NG method.
+        $results = $grouped_targets[$instance_id]->$methodNG($items, $a, $b);
 
-      if (isset($results)) {
-        // Collect results by entity.
-        // For hooks with array results, we merge results together.
-        // For hooks with scalar results, we collect results in an array.
-        foreach ($results as $id => $result) {
-          if (is_array($result)) {
-            $return[$id] = array_merge($return[$id], $result);
-          }
-          else {
-            $return[$id][] = $result;
+        if (isset($results)) {
+          // Collect results by entity.
+          // For hooks with array results, we merge results together.
+          // For hooks with scalar results, we collect results in an array.
+          foreach ($results as $id => $result) {
+            if (is_array($result)) {
+              $return[$id] = array_merge($return[$id], $result);
+            }
+            else {
+              $return[$id][] = $result;
+            }
           }
         }
       }
-    }
+      else {
+        // BC method.
+        $entities = $grouped_entities[$instance_id][$langcode];
+        $results = $grouped_targets[$instance_id]->$method($entities, $langcode, $items, $a, $b);
 
-    // Populate field values back in the entities, but avoid replacing missing
-    // fields with an empty array (those are not equivalent on update).
-    foreach ($grouped_entities[$instance_id] as $langcode => $entities) {
-      foreach ($entities as $id => $entity) {
-        if ($grouped_items[$instance_id][$langcode][$id] !== array() || isset($entity->{$field_name}[$langcode])) {
-          $entity->{$field_name}[$langcode] = $grouped_items[$instance_id][$langcode][$id];
+        if (isset($results)) {
+          // Collect results by entity.
+          // For hooks with array results, we merge results together.
+          // For hooks with scalar results, we collect results in an array.
+          foreach ($results as $id => $result) {
+            if (is_array($result)) {
+              $return[$id] = array_merge($return[$id], $result);
+            }
+            else {
+              $return[$id][] = $result;
+            }
+          }
+        }
+
+        // Populate field values back in the entities, but avoid replacing missing
+        // fields with an empty array (those are not equivalent on update).
+        foreach ($grouped_entities[$instance_id] as $langcode => $entities) {
+          foreach ($entities as $id => $entity) {
+            if ($grouped_items[$instance_id][$langcode][$id] !== array() || isset($entity->{$field_name}[$langcode])) {
+              $entity->{$field_name}[$langcode] = $grouped_items[$instance_id][$langcode][$id];
+            }
+          }
         }
       }
     }
diff --git a/core/modules/field/lib/Drupal/field/Plugin/Type/Formatter/FormatterBase.php b/core/modules/field/lib/Drupal/field/Plugin/Type/Formatter/FormatterBase.php
index fa780a5..d1d467d 100644
--- a/core/modules/field/lib/Drupal/field/Plugin/Type/Formatter/FormatterBase.php
+++ b/core/modules/field/lib/Drupal/field/Plugin/Type/Formatter/FormatterBase.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Entity\Field\FieldDefinitionInterface;
+use Drupal\Core\Entity\Field\Type\Field;
 use Drupal\field\FieldInstanceInterface;
 use Drupal\field\Plugin\PluginSettingsBase;
 
@@ -103,6 +104,45 @@ public function view(EntityInterface $entity, $langcode, array $items) {
     return $addition;
   }
 
+  // Formatter classes usually keep the base implementation of view() untouched,
+  // and override viewElements() instead. But view() is the entry point for the
+  // outside world./ If we provided the base implementation of viewNG() in the
+  // base class, the method_exists('viewNG') check would always return TRUE.
+  // We thus provide a "fake" base implementation, for child classes to
+  // explicitly call.
+  // Would probably be better off in a separate base class...
+  public function _viewNG(Field $items) {
+    $addition = array();
+
+    $elements = $this->viewElementsNG($items);
+    if ($elements) {
+      $entity = $items->getParent();
+      $entity_type = $entity->entityType();
+      $field_name = $this->fieldDefinition->getFieldName();
+      $info = array(
+        '#theme' => 'field',
+        '#title' => $this->fieldDefinition->getFieldLabel(),
+        '#access' => $this->checkFieldAccess('view', $entity),
+        '#label_display' => $this->label,
+        '#view_mode' => $this->viewMode,
+        '#language' => $entity->language()->langcode,
+        '#field_name' => $field_name,
+        '#field_type' => $this->fieldDefinition->getFieldType(),
+        '#field_translatable' => $this->fieldDefinition->isFieldTranslatable(),
+        '#entity_type' => $entity_type,
+        '#bundle' => $entity->bundle(),
+        '#object' => $entity,
+        // @todo Anything that uses #items should be converted as well...
+        '#items' => $items->getValue(),
+        '#formatter' => $this->getPluginId(),
+      );
+
+      $addition[$field_name] = array_merge($info, $elements);
+    }
+
+    return $addition;
+  }
+
   /**
    * {@inheritdoc}
    */
diff --git a/core/modules/field/lib/Drupal/field/Plugin/Type/Widget/WidgetBase.php b/core/modules/field/lib/Drupal/field/Plugin/Type/Widget/WidgetBase.php
index 5cf902b..4bc95be 100644
--- a/core/modules/field/lib/Drupal/field/Plugin/Type/Widget/WidgetBase.php
+++ b/core/modules/field/lib/Drupal/field/Plugin/Type/Widget/WidgetBase.php
@@ -10,6 +10,7 @@
 use Drupal\Component\Utility\NestedArray;
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Entity\Field\FieldDefinitionInterface;
+use Drupal\Core\Entity\Field\Type\Field;
 use Drupal\field\FieldInstanceInterface;
 use Drupal\field\Plugin\PluginSettingsBase;
 
@@ -53,6 +54,9 @@ public function __construct($plugin_id, array $plugin_definition, FieldDefinitio
 
   /**
    * {@inheritdoc}
+   *
+   * Note: for widgets, we probably need to provide an NG version of the
+   * whole form() / formMultipleElements() / formSingleElement() stack :-(...
    */
   public function form(EntityInterface $entity, $langcode, array $items, array &$form, array &$form_state, $get_delta = NULL) {
     $field_name = $this->fieldDefinition->getFieldName();
@@ -279,7 +283,7 @@ protected function formSingleElement(EntityInterface $entity, array $items, $del
   /**
    * {@inheritdoc}
    */
-  public function extractFormValues(EntityInterface $entity, $langcode, array &$items, array $form, array &$form_state) {
+  public function extractFormValuesNG(Field $items, $langcode, array $form, array &$form_state) {
     $field_name = $this->fieldDefinition->getFieldName();
 
     // Extract the values from $form_state['values'].
@@ -295,40 +299,52 @@ public function extractFormValues(EntityInterface $entity, $langcode, array &$it
       // Make sure the '_weight' entries are persisted in the process.
       $weights = array();
       if (isset($values[0]['_weight'])) {
-        foreach ($values as $delta => $value) {
-          $weights[$delta] = $value['_weight'];
+        foreach ($values as $delta => $item_values) {
+          $weights[$delta] = $item_values['_weight'];
         }
       }
-      $items = $this->massageFormValues($values, $form, $form_state);
+      $values = $this->massageFormValues($values, $form, $form_state);
 
-      foreach ($items as $delta => &$item) {
+      foreach ($values as $delta => &$item_values) {
         // Put back the weight.
         if (isset($weights[$delta])) {
-          $item['_weight'] = $weights[$delta];
+          $item_values['_weight'] = $weights[$delta];
         }
         // The tasks below are going to reshuffle deltas. Keep track of the
         // original deltas for correct reporting of errors in flagErrors().
-        $item['_original_delta'] = $delta;
+        $item_values['_original_delta'] = $delta;
       }
 
       // Account for drag-n-drop reordering.
-      $this->sortItems($items);
+      $this->sortItems($values);
 
       // Remove empty values.
-      $items = _field_filter_items($this->fieldDefinition->getFieldType(), $items);
+      // @todo: After https://drupal.org/node/1969728, "filter empty items" is
+      // done with $items->filterEmptyValues() on the NG $items.
+      $values = _field_filter_items($this->fieldDefinition->getFieldType(), $values);
 
-      // Put delta mapping in $form_state, so that flagErrors() can use it.
       $field_state = field_form_get_state($form['#parents'], $field_name, $langcode, $form_state);
-      foreach ($items as $delta => &$item) {
-        $field_state['original_deltas'][$delta] = $item['_original_delta'];
-        unset($item['_original_delta']);
+      foreach ($values as $delta => &$item_values) {
+        // Put delta mapping in $form_state, so that flagErrors() can use it.
+        $field_state['original_deltas'][$delta] = $item_values['_original_delta'];
+        unset($item_values['_original_delta']);
       }
       field_form_set_state($form['#parents'], $field_name, $langcode, $form_state, $field_state);
+
+      // Assign the values to the items.
+      $items->setValue($values);
     }
   }
 
   /**
    * {@inheritdoc}
+   *
+   * This is only kept to comply with WidgetInterface.
+   */
+  public function extractFormValues(EntityInterface $entity, $langcode, array &$items, array $form, array &$form_state) { }
+
+  /**
+   * {@inheritdoc}
    */
   public function flagErrors(EntityInterface $entity, $langcode, array $items, array $form, array &$form_state) {
     $field_name = $this->fieldDefinition->getFieldName();
diff --git a/core/modules/telephone/lib/Drupal/telephone/Plugin/field/formatter/TelephoneLinkFormatter.php b/core/modules/telephone/lib/Drupal/telephone/Plugin/field/formatter/TelephoneLinkFormatter.php
index 208d6bd..4362399 100644
--- a/core/modules/telephone/lib/Drupal/telephone/Plugin/field/formatter/TelephoneLinkFormatter.php
+++ b/core/modules/telephone/lib/Drupal/telephone/Plugin/field/formatter/TelephoneLinkFormatter.php
@@ -62,18 +62,18 @@ public function settingsSummary() {
   /**
    * {@inheritdoc}
    */
-  public function prepareView(array $entities, $langcode, array &$items) {
+  public function prepareViewNG(array $entities_items) {
     $settings = $this->getSettings();
 
-    foreach ($entities as $id => $entity) {
-      foreach ($items[$id] as &$item) {
+    foreach ($entities_items as $id => $items) {
+      foreach ($items as $item) {
         // If available, set custom link text.
         if (!empty($settings['title'])) {
-          $item['title'] = $settings['title'];
+          $item->set('title', $settings['title']);
         }
         // Otherwise, use telephone number itself as title.
         else {
-          $item['title'] = $item['value'];
+          $item->set('title', $item->value);
         }
       }
     }
diff --git a/core/modules/text/lib/Drupal/text/Plugin/field/formatter/TextDefaultFormatter.php b/core/modules/text/lib/Drupal/text/Plugin/field/formatter/TextDefaultFormatter.php
index 52b2388..7a78f4c 100644
--- a/core/modules/text/lib/Drupal/text/Plugin/field/formatter/TextDefaultFormatter.php
+++ b/core/modules/text/lib/Drupal/text/Plugin/field/formatter/TextDefaultFormatter.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\text\Plugin\field\formatter;
 
+use Drupal\Core\Entity\Field\Type\Field;
 use Drupal\field\Annotation\FieldFormatter;
 use Drupal\Core\Annotation\Translation;
 use Drupal\field\Plugin\Type\Formatter\FormatterBase;
@@ -31,18 +32,35 @@
  */
 class TextDefaultFormatter extends FormatterBase {
 
+  // See the hack in FormatterBase::_viewNG(). This should probabky go in a
+  // separate base class.
+  public function viewNG(Field $items) {
+    return parent::_viewNG($items);
+  }
+
   /**
-   * Implements Drupal\field\Plugin\Type\Formatter\FormatterInterface::viewElements().
+   * {@inheritdoc}
    */
-  public function viewElements(EntityInterface $entity, $langcode, array $items) {
+  public function viewElementsNG(Field $items) {
     $elements = array();
 
+    $langcode = $items->getParent()->language()->langcode;
     foreach ($items as $delta => $item) {
-      $output = text_sanitize($this->getFieldSetting('text_processing'), $langcode, $item, 'value');
+      // @todo Convert text_sanitize() to work on an NG $item (this requires
+      // http://drupal.org/node/1969728.)
+      $itemBC = $item->getValue(TRUE);
+      $output = text_sanitize($this->getFieldSetting('text_processing'), $langcode, $itemBC, 'value');
       $elements[$delta] = array('#markup' => $output);
     }
 
     return $elements;
   }
 
+  /**
+   * {@inheritdoc}
+   *
+   * This is only kept to comply with FormatterInterface.
+   */
+  public function viewElements(EntityInterface $entity, $langcode, array $items) { }
+
 }
diff --git a/core/modules/text/lib/Drupal/text/TextProcessed.php b/core/modules/text/lib/Drupal/text/TextProcessed.php
index 3a44722..7561d4f 100644
--- a/core/modules/text/lib/Drupal/text/TextProcessed.php
+++ b/core/modules/text/lib/Drupal/text/TextProcessed.php
@@ -82,9 +82,10 @@ public function getValue($langcode = NULL) {
    * Implements \Drupal\Core\TypedData\TypedDataInterface::setValue().
    */
   public function setValue($value, $notify = TRUE) {
-    if (isset($value)) {
-      throw new ReadOnlyException('Unable to set a computed property.');
-    }
+    // @todo: Commented out while we need to support BC entities.
+    //  if (isset($value)) {
+    //    throw new ReadOnlyException('Unable to set a computed property.');
+    //  }
   }
 
   /**
