diff --git a/core/modules/comment/lib/Drupal/comment/Plugin/Field/FieldFormatter/CommentDefaultFormatter.php b/core/modules/comment/lib/Drupal/comment/Plugin/Field/FieldFormatter/CommentDefaultFormatter.php
index bcdf86f..62df554 100644
--- a/core/modules/comment/lib/Drupal/comment/Plugin/Field/FieldFormatter/CommentDefaultFormatter.php
+++ b/core/modules/comment/lib/Drupal/comment/Plugin/Field/FieldFormatter/CommentDefaultFormatter.php
@@ -130,13 +130,13 @@ public function viewElements(FieldItemListInterface $items) {
         $this->currentUser->hasPermission('administer comments'))) {
         $mode = $comment_settings['default_mode'];
         $comments_per_page = $comment_settings['per_page'];
-        if ($cids = comment_get_thread($entity, $field_name, $mode, $comments_per_page, $this->settings['pager_id'])) {
+        if ($cids = comment_get_thread($entity, $field_name, $mode, $comments_per_page, $this->getSetting('pager_id'))) {
           $comments = $this->storageController->loadMultiple($cids);
           comment_prepare_thread($comments);
           $build = $this->viewBuilder->viewMultiple($comments);
           $build['pager']['#theme'] = 'pager';
-          if (!empty($this->settings['pager_id'])) {
-            $build['pager']['#element'] = $this->settings['pager_id'];
+          if ($this->getSetting('pager_id')) {
+            $build['pager']['#element'] = $this->getSetting('pager_id');
           }
           $output['comments'] = $build;
         }
diff --git a/core/modules/entity/entity.services.yml b/core/modules/entity/entity.services.yml
new file mode 100644
index 0000000..81ab979
--- /dev/null
+++ b/core/modules/entity/entity.services.yml
@@ -0,0 +1,4 @@
+services:
+  plugin.manager.entity.display_component_handler:
+    class: Drupal\entity\Plugin\Type\DisplayComponentHandlerPluginManager
+    parent: default_plugin_manager
diff --git a/core/modules/entity/lib/Drupal/entity/Annotation/DisplayComponent.php b/core/modules/entity/lib/Drupal/entity/Annotation/DisplayComponent.php
new file mode 100644
index 0000000..9a41976
--- /dev/null
+++ b/core/modules/entity/lib/Drupal/entity/Annotation/DisplayComponent.php
@@ -0,0 +1,26 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\entity\Annotation\DisplayComponent.
+ */
+
+namespace Drupal\entity\Annotation;
+
+use Drupal\Component\Annotation\Plugin;
+
+/**
+* Defines a DisplayComponent annotation object.
+*
+* @Annotation
+*/
+class DisplayComponent extends Plugin {
+
+/**
+  * The plugin ID.
+  *
+  * @var string
+  */
+  public $id;
+
+}
diff --git a/core/modules/entity/lib/Drupal/entity/DisplayComponentHandlerBase.php b/core/modules/entity/lib/Drupal/entity/DisplayComponentHandlerBase.php
new file mode 100644
index 0000000..3586976
--- /dev/null
+++ b/core/modules/entity/lib/Drupal/entity/DisplayComponentHandlerBase.php
@@ -0,0 +1,64 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\entity\DisplayComponentHandlerBase.
+ */
+
+namespace Drupal\entity;
+
+use Drupal\Component\Plugin\PluginBase;
+
+/**
+ * Provides a base class for DisplayComponentHandler plugins.
+ */
+abstract class DisplayComponentHandlerBase extends PluginBase implements DisplayComponentHandlerInterface {
+
+  /**
+   * The context in which the handler is being used.
+   *
+   * @var array
+   */
+  protected $context;
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setContext(array $context) {
+    $this->context = $context;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function prepareDisplayComponents(array &$components, array &$hidden_components) {
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function hasElement($name) {
+    return FALSE;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function massageIn($name, array $options) {
+    return $options;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function massageOut($properties) {
+    return $properties;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getRenderer($name, array $options) {
+  }
+
+}
diff --git a/core/modules/entity/lib/Drupal/entity/DisplayComponentHandlerInterface.php b/core/modules/entity/lib/Drupal/entity/DisplayComponentHandlerInterface.php
new file mode 100644
index 0000000..cbd3049
--- /dev/null
+++ b/core/modules/entity/lib/Drupal/entity/DisplayComponentHandlerInterface.php
@@ -0,0 +1,80 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\entity\DisplayComponentHandlerInterface.
+ */
+
+namespace Drupal\entity;
+
+/**
+ * Provides a base class for DisplayComponent plugins.
+ */
+interface DisplayComponentHandlerInterface {
+
+  /**
+   * Checks if the component handler has the passed element.
+   *
+   * @param string $name
+   *   The name of a display component.
+   *
+   * @return bool
+   *   TRUE if the display component handler provides the component.
+   */
+  public function hasElement($name);
+
+  /**
+   * Prepares the element options before set them to storage.
+   *
+   * @param string $name
+   *   The name of a display component.
+   * @param array $options
+   *   The options for this component.
+   *
+   * @return array
+   *   Massaged component options.
+   */
+  public function massageIn($name, array $options);
+
+  /**
+   * Sets the context for the rendering component.
+   *
+   * @param array $context
+   */
+  public function setContext(array $context);
+
+  /**
+   * Returns the render plugin for the display component.
+   *
+   * @param string $name
+   *   The name of a display component.
+   * @param array $options
+   *   The array of configuration options to instantiate render plugin.
+   *
+   * @return mixed
+   *   The object to render component or null.
+   */
+  public function getRenderer($name, array $options);
+
+  /**
+   * Prepares components when display created.
+   *
+   * @param array $components
+   *   A visible display components.
+   * @param array $hidden_components
+   *   A hidden display components.
+   */
+  public function prepareDisplayComponents(array &$components, array &$hidden_components);
+
+  /**
+   * Prepares the element options before passed to storage.
+   *
+   * @param array $properties
+   *   The entity display properties.
+   *
+   * return @array
+   *   An array of prepared properties of the display.
+   */
+  public function massageOut($properties);
+
+}
diff --git a/core/modules/entity/lib/Drupal/entity/Entity/EntityDisplay.php b/core/modules/entity/lib/Drupal/entity/Entity/EntityDisplay.php
index baf1cbd..ee543fc 100644
--- a/core/modules/entity/lib/Drupal/entity/Entity/EntityDisplay.php
+++ b/core/modules/entity/lib/Drupal/entity/Entity/EntityDisplay.php
@@ -35,40 +35,4 @@ class EntityDisplay extends EntityDisplayBase implements EntityViewDisplayInterf
    */
   protected $displayContext = 'view';
 
-  /**
-   * {@inheritdoc}
-   */
-  public function __construct(array $values, $entity_type) {
-    $this->pluginManager = \Drupal::service('plugin.manager.field.formatter');
-
-    parent::__construct($values, $entity_type);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getRenderer($field_name) {
-    if (isset($this->plugins[$field_name])) {
-      return $this->plugins[$field_name];
-    }
-
-    // Instantiate the formatter object from the stored display properties.
-    if (($configuration = $this->getComponent($field_name)) && isset($configuration['type']) && ($definition = $this->getFieldDefinition($field_name))) {
-      $formatter = $this->pluginManager->getInstance(array(
-        'field_definition' => $definition,
-        'view_mode' => $this->originalMode,
-        // No need to prepare, defaults have been merged in setComponent().
-        'prepare' => FALSE,
-        'configuration' => $configuration
-      ));
-    }
-    else {
-      $formatter = NULL;
-    }
-
-    // Persist the formatter object.
-    $this->plugins[$field_name] = $formatter;
-    return $formatter;
-  }
-
 }
diff --git a/core/modules/entity/lib/Drupal/entity/Entity/EntityFormDisplay.php b/core/modules/entity/lib/Drupal/entity/Entity/EntityFormDisplay.php
index ec22794..ca1bd5c 100644
--- a/core/modules/entity/lib/Drupal/entity/Entity/EntityFormDisplay.php
+++ b/core/modules/entity/lib/Drupal/entity/Entity/EntityFormDisplay.php
@@ -39,41 +39,12 @@ class EntityFormDisplay extends EntityDisplayBase implements EntityFormDisplayIn
    * {@inheritdoc}
    */
   public function __construct(array $values, $entity_type) {
-    $this->pluginManager = \Drupal::service('plugin.manager.field.widget');
-
     parent::__construct($values, $entity_type);
   }
 
   /**
    * {@inheritdoc}
    */
-  public function getRenderer($field_name) {
-    if (isset($this->plugins[$field_name])) {
-      return $this->plugins[$field_name];
-    }
-
-    // Instantiate the widget object from the stored display properties.
-    if (($configuration = $this->getComponent($field_name)) && isset($configuration['type']) && ($definition = $this->getFieldDefinition($field_name))) {
-      $widget = $this->pluginManager->getInstance(array(
-        'field_definition' => $definition,
-        'form_mode' => $this->originalMode,
-        // No need to prepare, defaults have been merged in setComponent().
-        'prepare' => FALSE,
-        'configuration' => $configuration
-      ));
-    }
-    else {
-      $widget = NULL;
-    }
-
-    // Persist the widget object.
-    $this->plugins[$field_name] = $widget;
-    return $widget;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
   public function serialize() {
     // Only store the definition, not external objects or derived data.
     $data = $this->getExportProperties() + array('entityType' => $this->getEntityTypeId());
diff --git a/core/modules/entity/lib/Drupal/entity/EntityDisplayBase.php b/core/modules/entity/lib/Drupal/entity/EntityDisplayBase.php
index afda40a..792e612 100644
--- a/core/modules/entity/lib/Drupal/entity/EntityDisplayBase.php
+++ b/core/modules/entity/lib/Drupal/entity/EntityDisplayBase.php
@@ -47,12 +47,6 @@
    */
   public $bundle;
 
-  /**
-   * A list of field definitions eligible for configuration in this display.
-   *
-   * @var \Drupal\Core\Field\FieldDefinitionInterface[]
-   */
-  protected $fieldDefinitions;
 
   /**
    * View or form mode to be displayed.
@@ -92,25 +86,28 @@
   public $originalMode;
 
   /**
-   * The plugin objects used for this display, keyed by field name.
+   * The renderer objects used for this display, keyed by component name.
+   */
+  protected $renderers = array();
+
+  /*
+   * The display component handler plugin manager.
    *
-   * @var array
+   * @var \Drupal\entity\Plugin\Type\DisplayComponentHandlerPluginManager
    */
-  protected $plugins = array();
+  protected $handlerManager;
 
   /**
-   * Context in which this entity will be used (e.g. 'display', 'form').
+   * Context in which this entity will be used (e.g. 'view', 'form').
    *
    * @var string
    */
   protected $displayContext;
 
   /**
-   * The plugin manager used by this entity type.
-   *
-   * @var \Drupal\Component\Plugin\PluginManagerBase
+   * A mapping of display elements and its corresponding handler
    */
-  protected $pluginManager;
+  protected $handlers;
 
   /**
    * {@inheritdoc}
@@ -124,16 +121,15 @@ public function __construct(array $values, $entity_type) {
     //   throw new \InvalidArgumentException('Missing required properties for an EntityDisplay entity.');
     // }
 
-    // A plugin manager and a context type needs to be set by extending classes.
-    if (!isset($this->pluginManager)) {
-      throw new \RuntimeException('Missing plugin manager.');
-    }
+
     if (!isset($this->displayContext)) {
       throw new \RuntimeException('Missing display context type.');
     }
 
     parent::__construct($values, $entity_type);
 
+    $this->handlerManager =\Drupal::service('plugin.manager.entity.display_component_handler');
+
     $this->originalMode = $this->mode;
 
     $this->init();
@@ -183,13 +179,10 @@ public function getExportProperties() {
       $properties[$name] = $this->get($name);
     }
 
-    // Do not store options for fields whose display is not set to be
-    // configurable.
-    foreach ($this->getFieldDefinitions() as $field_name => $definition) {
-      if (!$definition->isDisplayConfigurable($this->displayContext)) {
-        unset($properties['content'][$field_name]);
-        unset($properties['hidden'][$field_name]);
-      }
+    // Let the component handlers add missing components.
+    $handlers = $this->handlerManager->getDefinitions();
+    foreach (array_keys($handlers) as $type) {
+      $properties = $this->getComponentHandler($type)->massageOut($properties);
     }
 
     return $properties;
@@ -204,38 +197,10 @@ public function getExportProperties() {
    * - or that are not supposed to be configurable.
    */
   protected function init() {
-    // Fill in defaults for extra fields.
-    $extra_fields = field_info_extra_fields($this->targetEntityType, $this->bundle, ($this->displayContext == 'view' ? 'display' : $this->displayContext));
-    foreach ($extra_fields as $name => $definition) {
-      if (!isset($this->content[$name]) && !isset($this->hidden[$name])) {
-        // Extra fields are visible by default unless they explicitly say so.
-        if (!isset($definition['visible']) || $definition['visible'] == TRUE) {
-          $this->content[$name] = array(
-            'weight' => $definition['weight']
-          );
-        }
-        else {
-          $this->hidden[$name] = TRUE;
-        }
-      }
-    }
-
-    // Fill in defaults for fields.
-    $fields = $this->getFieldDefinitions();
-    foreach ($fields as $name => $definition) {
-      if (!$definition->isDisplayConfigurable($this->displayContext) || (!isset($this->content[$name]) && !isset($this->hidden[$name]))) {
-        $options = $definition->getDisplayOptions($this->displayContext);
-
-        if (!empty($options['type']) && $options['type'] == 'hidden') {
-          $this->hidden[$name] = TRUE;
-        }
-        elseif ($options) {
-          $this->content[$name] = $this->pluginManager->prepareConfiguration($definition->getType(), $options);
-        }
-        // Note: (base) fields that do not specify display options are not
-        // tracked in the display at all, in order to avoid cluttering the
-        // configuration that gets saved back.
-      }
+    // Let the component handlers add missing components.
+    $handlers = $this->handlerManager->getDefinitions();
+    foreach (array_keys($handlers) as $type) {
+      $this->getComponentHandler($type)->prepareDisplayComponents($this->content, $this->hidden);
     }
   }
 
@@ -272,14 +237,16 @@ public function setComponent($name, array $options = array()) {
       $options['weight'] = isset($max) ? $max + 1 : 0;
     }
 
-    // For a field, fill in default options.
-    if ($field_definition = $this->getFieldDefinition($name)) {
-      $options = $this->pluginManager->prepareConfiguration($field_definition->getType(), $options);
+    // Massage in some values
+    $handler = $this->getComponentHandlerByElementName($name);
+    if ($handler) {
+      // @todo sometimes handler not found.
+      $options = $handler->massageIn($name, $options);
     }
 
     $this->content[$name] = $options;
     unset($this->hidden[$name]);
-    unset($this->plugins[$name]);
+    unset($this->renderers[$name]);
 
     return $this;
   }
@@ -290,7 +257,6 @@ public function setComponent($name, array $options = array()) {
   public function removeComponent($name) {
     $this->hidden[$name] = TRUE;
     unset($this->content[$name]);
-    unset($this->plugins[$name]);
 
     return $this;
   }
@@ -315,41 +281,68 @@ public function getHighestWeight() {
   }
 
   /**
-   * Returns the field definition of a field.
+   * Finds component handler by element name.
+   *
+   * @param string $name
+   *   The element name.
+   *
+   * @return \Drupal\entity\DisplayComponentHandlerInterface
    */
-  protected function getFieldDefinition($field_name) {
-    $definitions = $this->getFieldDefinitions();
-    return isset($definitions[$field_name]) ? $definitions[$field_name] : NULL;
+  public function getComponentHandlerByElementName($name) {
+    if (!isset($this->handlers[$name])) {
+      $handlers = $this->handlerManager->getDefinitions();
+      foreach (array_keys($handlers) as $type) {
+        $handler = $this->getComponentHandler($type);
+        if ($handler && $handler->hasElement($name)) {
+          break;
+        }
+        $handler = NULL;
+      }
+      $this->handlers[$name] = $handler;
+    }
+
+    return $this->handlers[$name];
   }
 
   /**
-   * Returns the definitions of the fields that are candidate for display.
+   * Instantiates component handler.
+   *
+   * @param string $type
+   *   The type of component handler (field, extra_field).
+   *
+   * @return \Drupal\entity\DisplayComponentHandlerInterface
    */
-  protected function getFieldDefinitions() {
-    if (!isset($this->fieldDefinitions)) {
-      // @todo Replace this with \Drupal::entityManager()->getFieldDefinition()
-      //   when it can hand the $instance objects (and then reconsider the
-      //   $this->fieldDefinitions static cache ?)
-      //   https://drupal.org/node/2114707
-      $entity_manager = \Drupal::entityManager();
-      $entity_info = $entity_manager->getDefinition($this->targetEntityType);
-      $definitions = array();
-      if ($entity_info->isSubclassOf('\Drupal\Core\Entity\ContentEntityInterface')) {
-        $entity = _field_create_entity_from_ids((object) array('entity_type' => $this->targetEntityType, 'bundle' => $this->bundle, 'entity_id' => NULL));
-        foreach ($entity as $field_name => $items) {
-          $definitions[$field_name] = $items->getFieldDefinition();
-        }
-      }
+  public function getComponentHandler($type) {
+    $handler = $this->handlerManager->getInstance(array('type' => $type));
+    if ($handler) {
+      $handler->setContext(array(
+        'entity_type' => $this->targetEntityType,
+        'bundle' => $this->bundle,
+        'view_mode' => $this->originalMode,
+        'display_context' => $this->displayContext,
+      ));
+     }
+    return $handler;
+  }
 
-      // The display only cares about fields that specify display options.
-      // Discard base fields that are not rendered through formatters / widgets.
-      $display_context = $this->displayContext;
-      $this->fieldDefinitions = array_filter($definitions, function (FieldDefinitionInterface $definition) use ($display_context) {
-        return $definition->getDisplayOptions($display_context);
-      });
+  /**+
+   * {@inheritdoc}
+   */
+  public function getRenderer($name) {
+    if (!isset($this->content[$name])) {
+      return NULL;
     }
 
-    return $this->fieldDefinitions;
+    if (!array_key_exists($name, $this->renderers)) {
+      if ($handler = $this->getComponentHandlerByElementName($name)) {
+        $options = $this->getComponent($name);
+        $this->renderers[$name] = $handler->getRenderer($name, $options);
+      }
+      else {
+        $this->renderers[$name] = NULL;
+      }
+    }
+    return $this->renderers[$name];
   }
 
 }
diff --git a/core/modules/entity/lib/Drupal/entity/Plugin/DisplayComponent/ExtraFieldDisplayComponentHandler.php b/core/modules/entity/lib/Drupal/entity/Plugin/DisplayComponent/ExtraFieldDisplayComponentHandler.php
new file mode 100644
index 0000000..3363071
--- /dev/null
+++ b/core/modules/entity/lib/Drupal/entity/Plugin/DisplayComponent/ExtraFieldDisplayComponentHandler.php
@@ -0,0 +1,50 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\entity\Plugin\DisplayComponent\ExtraFieldDisplayComponentHandler.
+ */
+
+namespace Drupal\entity\Plugin\DisplayComponent;
+
+use Drupal\entity\DisplayComponentHandlerBase;
+
+/**
+ * Provides a component handler to manage entity extra fields.
+ *
+ * @DisplayComponent(
+ *   id = "extra_field"
+ * )
+ */
+class ExtraFieldDisplayComponentHandler extends DisplayComponentHandlerBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function prepareDisplayComponents(array &$components, array &$hidden_components) {
+    // Fill in defaults for extra fields.
+    $extra_fields = field_info_extra_fields($this->context['entity_type'], $this->context['bundle'], ($this->context['display_context'] == 'view' ? 'display' : $this->context['display_context']));
+    foreach ($extra_fields as $name => $definition) {
+      if (!isset($components[$name]) && !isset($hidden_components[$name])) {
+        // Extra fields are visible by default unless they explicitly say so.
+        if (!isset($definition['visible']) || $definition['visible'] == TRUE) {
+          $components[$name] = array(
+            'weight' => $definition['weight']
+          );
+        }
+        else {
+          $hidden_components[$name] = TRUE;
+        }
+      }
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function hasElement($name) {
+    $extra_fields = field_info_extra_fields($this->context['entity_type'], $this->context['bundle'], ($this->context['display_context'] == 'view' ? 'display' : $this->context['display_context']));
+    return isset($extra_fields[$name]);
+  }
+
+}
diff --git a/core/modules/entity/lib/Drupal/entity/Plugin/Type/DisplayComponentHandlerPluginManager.php b/core/modules/entity/lib/Drupal/entity/Plugin/Type/DisplayComponentHandlerPluginManager.php
new file mode 100644
index 0000000..1081065
--- /dev/null
+++ b/core/modules/entity/lib/Drupal/entity/Plugin/Type/DisplayComponentHandlerPluginManager.php
@@ -0,0 +1,65 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\entity\Plugin\Type\DisplayComponentHandlerPluginManager.
+ */
+
+namespace Drupal\entity\Plugin\Type;
+
+use Drupal\Core\Cache\CacheBackendInterface;
+use Drupal\Core\Extension\ModuleHandlerInterface;
+use Drupal\Core\Language\LanguageManager;
+use Drupal\Core\Plugin\DefaultPluginManager;
+
+/**
+ * Manages entity display component handlers.
+ *
+ * The handlers are typically shared for the whole request. getInstance() holds
+ * the instantiated plugins and only instantiates one of each type.
+ *
+ * @see hook_display_component_handler_info_alter()
+ */
+class DisplayComponentHandlerPluginManager extends DefaultPluginManager {
+
+ /**
+  * The handlers that have already been instantiated by getInstance().
+  *
+  * @var array
+  */
+ protected $plugins = array();
+
+ /**
+  * Constructs a DisplayComponentHandlerPluginManager object.
+  *
+  * @param \Traversable $namespaces
+  *   An object that implements \Traversable which contains the root paths
+  *   keyed by the corresponding namespace to look for plugin implementations.
+  * @param \Drupal\Core\Cache\CacheBackendInterface $cache_backend
+  *   Cache backend instance to use.
+  * @param \Drupal\Core\Language\LanguageManager $language_manager
+  *   The language manager.
+  * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
+  *   The module handler to invoke the alter hook with.
+  */
+ public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, LanguageManager $language_manager, ModuleHandlerInterface $module_handler) {
+   parent::__construct('Plugin/DisplayComponent', $namespaces, 'Drupal\entity\Annotation\DisplayComponent');
+   // @todo Document the alter hook.
+   $this->alterInfo($module_handler, 'display_component_handler_info');
+   $this->setCacheBackend($cache_backend, $language_manager, 'display_component_handlers');
+ }
+
+ /**
+  * {@inheritdoc}
+  */
+ public function getInstance(array $options) {
+   $plugin_id = $options['type'];
+
+   if (!isset($this->plugins[$plugin_id]) && !array_key_exists($plugin_id, $this->plugins)) {
+     $this->plugins[$plugin_id] = $this->discovery->getDefinition($plugin_id) ? $this->createInstance($plugin_id) : NULL;
+    }
+
+    return $this->plugins[$plugin_id];
+  }
+
+}
diff --git a/core/modules/field/lib/Drupal/field/Plugin/DisplayComponent/FieldDisplayComponentHandler.php b/core/modules/field/lib/Drupal/field/Plugin/DisplayComponent/FieldDisplayComponentHandler.php
new file mode 100644
index 0000000..b56f459
--- /dev/null
+++ b/core/modules/field/lib/Drupal/field/Plugin/DisplayComponent/FieldDisplayComponentHandler.php
@@ -0,0 +1,223 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\field\Plugin\DisplayComponent\FieldDisplayComponentHandler.
+ */
+
+namespace Drupal\field\Plugin\DisplayComponent;
+
+use Drupal\Core\Field\FieldDefinitionInterface;
+use Drupal\Core\Field\FormatterPluginManager;
+use Drupal\Core\Field\WidgetPluginManager;
+use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
+use Drupal\entity\DisplayComponentHandlerBase;
+use Drupal\field\FieldInfo;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * Provides a component handler to manage entity fields.
+ *
+ * @DisplayComponent(
+ *   id = "field"
+ * )
+ */
+class FieldDisplayComponentHandler extends DisplayComponentHandlerBase implements ContainerFactoryPluginInterface {
+
+  /**
+   * The field info service.
+   *
+   * @var \Drupal\field\FieldInfo
+   */
+  protected $fieldInfo;
+
+  /**
+   * The field formatter plugin manager.
+   *
+   * @var \Drupal\Core\Field\FormatterPluginManager
+   */
+  protected $formatterPluginManager;
+
+  /**
+   * The field widget plugin manager.
+   *
+   * @var \Drupal\Core\Field\WidgetPluginManager
+   */
+  protected $widgetPluginManager;
+
+  /**
+   * A list of field definitions eligible for configuration in this display.
+   *
+   * @var \Drupal\Core\Field\FieldDefinitionInterface[]
+   */
+  protected $fieldDefinitions;
+
+  /**
+   * Constructs a FieldDisplayComponentHandler object.
+   *
+   * @param array $configuration
+   *   A configuration array containing information about the plugin instance.
+   * @param string $plugin_id
+   *   The plugin ID for the plugin instance.
+   * @param array $plugin_definition
+   *   The plugin implementation definition.
+   * @param \Drupal\field\FieldInfo $field_info
+   *   The field info service.
+   * @param \Drupal\Core\Field\FormatterPluginManager $formatter_plugin_manager
+   *   The field formatter plugin manager.
+   * @param \Drupal\Core\Field\WidgetPluginManager $widget_plugin_manager
+   *   The field widget plugin manager.
+   */
+  public function __construct(array $configuration, $plugin_id, array $plugin_definition, FieldInfo $field_info, FormatterPluginManager $formatter_plugin_manager, WidgetPluginManager $widget_plugin_manager) {
+    parent::__construct($configuration, $plugin_id, $plugin_definition);
+
+    $this->fieldInfo = $field_info;
+    $this->formatterPluginManager = $formatter_plugin_manager;
+    $this->widgetPluginManager = $widget_plugin_manager;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container, array $configuration, $plugin_id, array $plugin_definition) {
+    return new static($configuration, $plugin_id, $plugin_definition,
+      $container->get('field.info'),
+      $container->get('plugin.manager.field.formatter'),
+      $container->get('plugin.manager.field.widget')
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function massageIn($name, array $options) {
+    $field_definition = $this->getFieldDefinition($name);
+    if (!isset($field_definition)) {
+      // The field in process of removal from display.
+      return $options;
+    }
+    if ($this->context['display_context'] == 'view') {
+      return $this->formatterPluginManager->prepareConfiguration($field_definition->getType(), $options);
+    }
+    else {
+      return $this->widgetPluginManager->prepareConfiguration($field_definition->getType(), $options);
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function massageOut($properties) {
+    // Do not store options for fields whose display is not set to be
+    // configurable.
+    foreach ($this->getFieldDefinitions() as $field_name => $definition) {
+      if (!$definition->isDisplayConfigurable($this->context['display_context'])) {
+        unset($properties['content'][$field_name]);
+        unset($properties['hidden'][$field_name]);
+      }
+    }
+
+    return $properties;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function prepareDisplayComponents(array &$components, array &$hidden_components) {
+    if ($this->context['display_context'] == 'view') {
+      $plugin_manager = $this->formatterPluginManager;
+    }
+    else {
+      $plugin_manager = $this->widgetPluginManager;
+    }
+
+    // Fill in defaults for fields.
+    $fields = $this->getFieldDefinitions();
+    foreach ($fields as $name => $definition) {
+      if (!$definition->isDisplayConfigurable($this->context['display_context']) || (!isset($components[$name]) && !isset($hidden_components[$name]))) {
+        $options = $definition->getDisplayOptions($this->context['display_context']);
+
+        if (!empty($options['type']) && $options['type'] == 'hidden') {
+          $hidden_components[$name] = TRUE;
+        }
+        elseif ($options) {
+          $components[$name] = $plugin_manager->prepareConfiguration($definition->getType(), $options);
+        }
+        // Note: (base) fields that do not specify display options are not
+        // tracked in the display at all, in order to avoid cluttering the
+        // configuration that gets saved back.
+      }
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getRenderer($name, array $options) {
+    if (isset($options['type']) && ($definition = $this->getFieldDefinition($name))) {
+      if ($this->context['display_context'] == 'view') {
+        $plugin_manager = $this->formatterPluginManager;
+        $mode_key = 'view_mode';
+      }
+      else {
+        $plugin_manager = $this->widgetPluginManager;
+        $mode_key = 'form_mode';
+      }
+
+      return $plugin_manager->getInstance(array(
+        'field_definition' => $definition,
+        $mode_key => $this->context['view_mode'],
+        // No need to prepare, defaults have been merged when the options were
+        // written in the display.
+        'prepare' => FALSE,
+        'configuration' => $options,
+      ));
+    }
+    return NULL;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function hasElement($name) {
+    $field_defintion = $this->getFieldDefinition($name);
+    return isset($field_defintion);
+  }
+
+  /**
+   * Returns the field definition of a field.
+   */
+  protected function getFieldDefinition($field_name) {
+    $definitions = $this->getFieldDefinitions();
+    return isset($definitions[$field_name]) ? $definitions[$field_name] : NULL;
+  }
+
+  /**
+   * Returns the definitions of the fields that are candidate for display.
+   */
+  protected function getFieldDefinitions() {
+    // @todo Replace this with \Drupal::entityManager()->getFieldDefinition()
+    //   when it can hand the $instance objects (and then reconsider the
+    //   $this->fieldDefinitions static cache ?)
+    //   https://drupal.org/node/2114707
+    $entity_manager = \Drupal::entityManager();
+    $entity_info = $entity_manager->getDefinition($this->context['entity_type']);
+    $definitions = array();
+    if ($entity_info->isSubclassOf('\Drupal\Core\Entity\ContentEntityInterface')) {
+      $entity = _field_create_entity_from_ids((object) array('entity_type' => $this->context['entity_type'], 'bundle' => $this->context['bundle'], 'entity_id' => NULL));
+      foreach ($entity as $field_name => $items) {
+        $definitions[$field_name] = $items->getFieldDefinition();
+      }
+    }
+
+    // The display only cares about fields that specify display options.
+    // Discard base fields that are not rendered through formatters / widgets.
+    $display_context = $this->context['display_context'];
+    $this->fieldDefinitions = array_filter($definitions, function (FieldDefinitionInterface $definition) use ($display_context) {
+      return $definition->getDisplayOptions($display_context);
+    });
+
+    return $this->fieldDefinitions;
+  }
+
+}
