diff --git a/core/modules/field/field.api.php b/core/modules/field/field.api.php
index d77eca1..cf186c6 100644
--- a/core/modules/field/field.api.php
+++ b/core/modules/field/field.api.php
@@ -687,13 +687,18 @@ function hook_field_is_empty($item, $field) {
  * Field API widgets specify how fields are displayed in edit forms. Fields of a
  * given @link field_types field type @endlink may be edited using more than one
  * widget. In this case, the Field UI module allows the site builder to choose
- * which widget to use. Widget types are defined by implementing
+ * which widget to use.
+ *
+ * Widgets are Plugins managed by the Drupal\field\Plugin\WidgetPluginManager
+ * class. A widget is implemented by providing a class that implements
+ * Drupal\field\Field\Widget\WidgetInterface (in most cases, by subclassing
+ * Drupal\field\Field\Widget\WidgetBase), and exposed by implementing
  * hook_field_widget_info().
  *
  * Widgets are @link forms_api_reference.html Form API @endlink
- * elements with additional processing capabilities. Widget hooks are typically
- * called by the Field Attach API during the creation of the field form
- * structure with field_attach_form().
+ * elements with additional processing capabilities. The methods of the
+ * WidgetInterface object are typically called by the Field Attach API during
+ * the creation of the field form structure with field_attach_form().
  *
  * @see field
  * @see field_types
@@ -710,60 +715,46 @@ function hook_field_is_empty($item, $field) {
  *   The values are arrays describing the widget type, with the following
  *   key/value pairs:
  *   - label: The human-readable name of the widget type.
- *   - description: A short description for the widget type.
+ *   - class: The (namespaced) name of the class that implements the widget.
  *   - field types: An array of field types the widget supports.
  *   - settings: An array whose keys are the names of the settings available
  *     for the widget type, and whose values are the default values for those
  *     settings.
+ *   - multiple_values: A boolean indicating whether the widget allows the input
+ *     of multiple field value.
+ *       - TRUE: (default) The widget will be repeated for each value input.
+ *       - FALSE: One single copy of the widget can handle several field values.
+ *         Examples: checkboxes, multiple select, comma-separated textfield...
  *   - behaviors: (optional) An array describing behaviors of the widget, with
  *     the following elements:
- *     - multiple values: One of the following constants:
- *       - FIELD_BEHAVIOR_DEFAULT: (default) If the widget allows the input of
- *         one single field value (most common case). The widget will be
- *         repeated for each value input.
- *       - FIELD_BEHAVIOR_CUSTOM: If one single copy of the widget can receive
- *         several field values. Examples: checkboxes, multiple select,
- *         comma-separated textfield.
  *     - default value: One of the following constants:
  *       - FIELD_BEHAVIOR_DEFAULT: (default) If the widget accepts default
  *         values.
  *       - FIELD_BEHAVIOR_NONE: if the widget does not support default values.
  *
  * @see hook_field_widget_info_alter()
- * @see hook_field_widget_form()
  * @see hook_field_widget_form_alter()
  * @see hook_field_widget_WIDGET_TYPE_form_alter()
- * @see hook_field_widget_error()
- * @see hook_field_widget_settings_form()
  */
 function hook_field_widget_info() {
-    return array(
+  return array(
     'text_textfield' => array(
       'label' => t('Text field'),
+      'class' => '\Drupal\text\Field\Widget\TextfieldWidget',
       'field types' => array('text'),
       'settings' => array('size' => 60),
-      'behaviors' => array(
-        'multiple values' => FIELD_BEHAVIOR_DEFAULT,
-        'default value' => FIELD_BEHAVIOR_DEFAULT,
-      ),
     ),
     'text_textarea' => array(
       'label' => t('Text area (multiple rows)'),
+      'class' => '\Drupal\text\Field\Widget\TextareaWidget',
       'field types' => array('text_long'),
       'settings' => array('rows' => 5),
-      'behaviors' => array(
-        'multiple values' => FIELD_BEHAVIOR_DEFAULT,
-        'default value' => FIELD_BEHAVIOR_DEFAULT,
-      ),
     ),
     'text_textarea_with_summary' => array(
       'label' => t('Text area with a summary'),
+      'class' => '\Drupal\text\Field\Widget\TextareaWithSummaryWidget',
       'field types' => array('text_with_summary'),
       'settings' => array('rows' => 9, 'summary_rows' => 3),
-      'behaviors' => array(
-        'multiple values' => FIELD_BEHAVIOR_DEFAULT,
-        'default value' => FIELD_BEHAVIOR_DEFAULT,
-      ),
     ),
   );
 }
@@ -786,92 +777,6 @@ function hook_field_widget_info_alter(&$info) {
 }
 
 /**
- * Return the form for a single field widget.
- *
- * Field widget form elements should be based on the passed-in $element, which
- * contains the base form element properties derived from the field
- * configuration.
- *
- * Field API will set the weight, field name and delta values for each form
- * element. If there are multiple values for this field, the Field API will
- * invoke this hook as many times as needed.
- *
- * Note that, depending on the context in which the widget is being included
- * (regular entity form, field configuration form, advanced search form...),
- * the values for $field and $instance might be different from the "official"
- * definitions returned by field_info_field() and field_info_instance().
- * Examples: mono-value widget even if the field is multi-valued, non-required
- * widget even if the field is 'required'...
- *
- * Therefore, the FAPI element callbacks (such as #process, #element_validate,
- * #value_callback...) used by the widget cannot use the field_info_field()
- * or field_info_instance() functions to retrieve the $field or $instance
- * definitions they should operate on. The field_widget_field() and
- * field_widget_instance() functions should be used instead to fetch the
- * current working definitions from $form_state, where Field API stores them.
- *
- * Alternatively, hook_field_widget_form() can extract the needed specific
- * properties from $field and $instance and set them as ad-hoc
- * $element['#custom'] properties, for later use by its element callbacks.
- *
- * Other modules may alter the form element provided by this function using
- * hook_field_widget_form_alter().
- *
- * @param $form
- *   The form structure where widgets are being attached to. This might be a
- *   full form structure, or a sub-element of a larger form.
- * @param $form_state
- *   An associative array containing the current state of the form.
- * @param $field
- *   The field structure.
- * @param $instance
- *   The field instance.
- * @param $langcode
- *   The language associated with $items.
- * @param $items
- *   Array of default values for this field.
- * @param $delta
- *   The order of this item in the array of subelements (0, 1, 2, etc).
- * @param $element
- *   A form element array containing basic properties for the widget:
- *   - #entity_type: The name of the entity the field is attached to.
- *   - #bundle: The name of the field bundle the field is contained in.
- *   - #field_name: The name of the field.
- *   - #language: The language the field is being edited in.
- *   - #field_parents: The 'parents' space for the field in the form. Most
- *       widgets can simply overlook this property. This identifies the
- *       location where the field values are placed within
- *       $form_state['values'], and is used to access processing information
- *       for the field through the field_form_get_state() and
- *       field_form_set_state() functions.
- *   - #columns: A list of field storage columns of the field.
- *   - #title: The sanitized element label for the field instance, ready for
- *     output.
- *   - #description: The sanitized element description for the field instance,
- *     ready for output.
- *   - #required: A Boolean indicating whether the element value is required;
- *     for required multiple value fields, only the first widget's values are
- *     required.
- *   - #delta: The order of this item in the array of subelements; see $delta
- *     above.
- *
- * @return
- *   The form elements for a single widget for this field.
- *
- * @see field_widget_field()
- * @see field_widget_instance()
- * @see hook_field_widget_form_alter()
- * @see hook_field_widget_WIDGET_TYPE_form_alter()
- */
-function hook_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) {
-  $element += array(
-    '#type' => $instance['widget']['type'],
-    '#default_value' => isset($items[$delta]) ? $items[$delta] : '',
-  );
-  return $element;
-}
-
-/**
  * Alter forms for field widgets provided by other modules.
  *
  * @param $element
@@ -972,30 +877,6 @@ function hook_field_widget_properties_alter(&$widget, $context) {
 }
 
 /**
- * Flag a field-level validation error.
- *
- * @param $element
- *   An array containing the form element for the widget. The error needs to be
- *   flagged on the right sub-element, according to the widget's internal
- *   structure.
- * @param $error
- *   An associative array with the following key-value pairs, as returned by
- *   hook_field_validate():
- *   - error: the error code. Complex widgets might need to report different
- *     errors to different form elements inside the widget.
- *   - message: the human readable message to be displayed.
- * @param $form
- *   The form structure where field elements are attached to. This might be a
- *   full form structure, or a sub-element of a larger form.
- * @param $form_state
- *   An associative array containing the current state of the form.
- */
-function hook_field_widget_error($element, $error, $form, &$form_state) {
-  form_error($element, $error['message']);
-}
-
-
-/**
  * @} End of "defgroup field_widget".
  */
 
diff --git a/core/modules/field/field.attach.inc b/core/modules/field/field.attach.inc
index 611b577..bdc571c 100644
--- a/core/modules/field/field.attach.inc
+++ b/core/modules/field/field.attach.inc
@@ -7,6 +7,7 @@
 
 use Drupal\field\FieldValidationException;
 use Drupal\entity\EntityInterface;
+use Drupal\field\Field\FieldWidgetBridge;
 
 /**
  * @defgroup field_storage Field Storage API
@@ -163,6 +164,7 @@ function _field_invoke($op, $entity_type, EntityInterface $entity, &$a = NULL, &
     'default' => FALSE,
     'deleted' => FALSE,
     'langcode' => NULL,
+    'target_closure' => NULL,
   );
   $options += $default_options;
 
@@ -176,15 +178,31 @@ function _field_invoke($op, $entity_type, EntityInterface $entity, &$a = NULL, &
     // field_info_field_by_id().
     $field = field_info_field_by_id($instance['field_id']);
     $field_name = $field['field_name'];
-    $function = $options['default'] ? 'field_default_' . $op : $field['module'] . '_field_' . $op;
-    if (function_exists($function)) {
+
+    // Temporary compatibility layer: accept both old-style function calls and
+    //
+    if (isset($options['target_closure'])) {
+      $object = $options['target_closure']($instance);
+      $callable = array($object, $op);
+    }
+    else {
+      $callable = $options['default'] ? 'field_default_' . $op : $field['module'] . '_field_' . $op;
+    }
+
+    if (is_callable($callable)) {
       // 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) {
         $items = isset($entity->{$field_name}[$langcode]) ? $entity->{$field_name}[$langcode] : array();
-        $result = $function($entity_type, $entity, $field, $instance, $langcode, $items, $a, $b);
+
+        if (isset($options['target_closure'])) {
+          $result = $object->$op($entity, $langcode, $items, $a, $b);
+        }
+        else {
+          $result = $callable($entity_type, $entity, $field, $instance, $langcode, $items, $a, $b);
+        }
         if (isset($result)) {
           // For hooks with array results, we merge results together.
           // For hooks with scalar results, we collect results in an array.
@@ -432,6 +450,15 @@ function _field_invoke_get_instances($entity_type, $bundle, $options) {
 }
 
 /**
+ * @todo
+ */
+function _field_invoke_widget_target() {
+  return function ($instance) {
+    return $instance->getWidget();
+  };
+}
+
+/**
  * Add form elements for all fields for an entity to a form structure.
  *
  * The form elements for the entity's fields are added by reference as direct
@@ -542,8 +569,11 @@ function field_attach_form($entity_type, EntityInterface $entity, &$form, &$form
   $form += array('#parents' => array());
 
   // If no language is provided use the default site language.
-  $options = array('langcode' => field_valid_language($langcode));
-  $form += (array) _field_invoke_default('form', $entity_type, $entity, $form, $form_state, $options);
+  $options = array(
+    'langcode' => field_valid_language($langcode),
+    'target_closure' => _field_invoke_widget_target(),
+  );
+  $form += (array) _field_invoke('form', $entity_type, $entity, $form, $form_state, $options);
 
   // Add custom weight handling.
   $form['#pre_render'][] = '_field_extra_fields_pre_render';
@@ -796,7 +826,10 @@ function field_attach_validate($entity_type, $entity) {
  */
 function field_attach_form_validate($entity_type, EntityInterface $entity, $form, &$form_state) {
   // Extract field values from submitted values.
-  _field_invoke_default('extract_form_values', $entity_type, $entity, $form, $form_state);
+  $options = array(
+    'target_closure' => _field_invoke_widget_target(),
+  );
+  _field_invoke('extractFormValues', $entity_type, $entity, $form, $form_state, $options);
 
   // Perform field_level validation.
   try {
@@ -812,7 +845,7 @@ function field_attach_form_validate($entity_type, EntityInterface $entity, $form
         field_form_set_state($form['#parents'], $field_name, $langcode, $form_state, $field_state);
       }
     }
-    _field_invoke_default('form_errors', $entity_type, $entity, $form, $form_state);
+    _field_invoke('flagErrors', $entity_type, $entity, $form, $form_state, $options);
   }
 }
 
@@ -836,9 +869,11 @@ function field_attach_form_validate($entity_type, EntityInterface $entity, $form
  */
 function field_attach_submit($entity_type, EntityInterface $entity, $form, &$form_state) {
   // Extract field values from submitted values.
-  _field_invoke_default('extract_form_values', $entity_type, $entity, $form, $form_state);
-
-  _field_invoke_default('submit', $entity_type, $entity, $form, $form_state);
+  $options = array(
+    'target_closure' => _field_invoke_widget_target(),
+  );
+  _field_invoke('extractFormValues', $entity_type, $entity, $form, $form_state, $options);
+  _field_invoke('submit', $entity_type, $entity, $form, $form_state, $options);
 
   // Let other modules act on submitting the entity.
   // Avoid module_invoke_all() to let $form_state be taken by reference.
diff --git a/core/modules/field/field.crud.inc b/core/modules/field/field.crud.inc
index b748c51..77c3c5c 100644
--- a/core/modules/field/field.crud.inc
+++ b/core/modules/field/field.crud.inc
@@ -323,7 +323,11 @@ function field_read_field($field_name, $include_additional = array()) {
  * Reads in fields that match an array of conditions.
  *
  * @param array $params
- *   An array of conditions to match against.
+ *   An array of conditions to match against. Keys are columns from the
+ *   'field_config' table, values are conditions to match. Additionally,
+ *   conditions on the 'entity_type' and 'bundle' columns from the
+ *   'field_config_instance' table are supported (select fields having an
+ *   instance on a given bundle).
  * @param array $include_additional
  *   The default behavior of this function is to not return fields that
  *   are inactive or have been deleted. Setting
@@ -341,8 +345,18 @@ function field_read_fields($params = array(), $include_additional = array()) {
 
   // Turn the conditions into a query.
   foreach ($params as $key => $value) {
+    // Allow filtering on the 'entity_type' and 'bundle' columns of the
+    // field_config_instance table.
+    if ($key == 'entity_type' || $key == 'bundle') {
+      if (empty($fci_join)) {
+        $fci_join = $query->join('field_config_instance', 'fci', 'fc.id = fci.field_id');
+      }
+      $key = 'fci.' . $key;
+    }
+
     $query->condition($key, $value);
   }
+
   if (!isset($include_additional['include_inactive']) || !$include_additional['include_inactive']) {
     $query
       ->condition('fc.active', 1)
@@ -559,6 +573,14 @@ function _field_write_instance($instance, $update = FALSE) {
   $field = field_read_field($instance['field_name']);
   $field_type = field_info_field_types($field['type']);
 
+  // Temporary workaround to allow incoming $instance as arrays or classed
+  // objects.
+  // @todo remove once the external APIs have been converted to use
+  // FieldInstance objects.
+  if (is_object($instance) && get_class($instance) == 'Drupal\field\Field\FieldInstance') {
+    $instance = $instance->getArray();
+  }
+
   // Set defaults.
   $instance += array(
     'settings' => array(),
diff --git a/core/modules/field/field.default.inc b/core/modules/field/field.default.inc
index b4a6f50..7d1a309 100644
--- a/core/modules/field/field.default.inc
+++ b/core/modules/field/field.default.inc
@@ -11,39 +11,6 @@
  */
 
 /**
- * Extracts field values from submitted form values.
- *
- * @param $entity_type
- *   The type of $entity.
- * @param $entity
- *   The entity for the operation.
- * @param $field
- *   The field structure for the operation.
- * @param $instance
- *   The instance structure for $field on $entity's bundle.
- * @param $langcode
- *   The language associated to $items.
- * @param $items
- *   The field values. This parameter is altered by reference to receive the
- *   incoming form values.
- * @param $form
- *   The form structure where field elements are attached to. This might be a
- *   full form structure, or a sub-element of a larger form.
- * @param $form_state
- *   The form state.
- */
-function field_default_extract_form_values($entity_type, $entity, $field, $instance, $langcode, &$items, $form, &$form_state) {
-  $path = array_merge($form['#parents'], array($field['field_name'], $langcode));
-  $key_exists = NULL;
-  $values = drupal_array_get_nested_value($form_state['values'], $path, $key_exists);
-  if ($key_exists) {
-    // Remove the 'value' of the 'add more' button.
-    unset($values['add_more']);
-    $items = $values;
-  }
-}
-
-/**
  * Generic field validation handler.
  *
  * Possible error codes:
@@ -86,13 +53,6 @@ function field_default_validate($entity_type, $entity, $field, $instance, $langc
   }
 }
 
-function field_default_submit($entity_type, $entity, $field, $instance, $langcode, &$items, $form, &$form_state) {
-  // Filter out empty values.
-  $items = _field_filter_items($field, $items);
-  // Reorder items to account for drag-n-drop reordering.
-  $items = _field_sort_items($field, $items);
-}
-
 /**
  * Default field 'insert' operation.
  *
diff --git a/core/modules/field/field.form.inc b/core/modules/field/field.form.inc
index 44a221f..b473a53 100644
--- a/core/modules/field/field.form.inc
+++ b/core/modules/field/field.form.inc
@@ -6,290 +6,6 @@
  */
 
 /**
- * Creates a form element for a field and can populate it with a default value.
- *
- * If the form element is not associated with an entity (i.e., $entity is NULL)
- * field_get_default_value will be called to supply the default value for the
- * field. Also allows other modules to alter the form element by implementing
- * their own hooks.
- *
- * @param $entity_type
- *   The type of entity (for example 'node' or 'user') that the field belongs
- *   to.
- * @param $entity
- *   The entity object that the field belongs to. This may be NULL if creating a
- *   form element with a default value.
- * @param $field
- *   An array representing the field whose editing element is being created.
- * @param $instance
- *   An array representing the structure for $field in its current context.
- * @param $langcode
- *   The language associated with the field.
- * @param $items
- *   An array of the field values. When creating a new entity this may be NULL
- *   or an empty array to use default values.
- * @param $form
- *   An array representing the form that the editing element will be attached
- *   to.
- * @param $form_state
- *   An array containing the current state of the form.
- * @param $get_delta
- *   Used to get only a specific delta value of a multiple value field.
- *
- * @return
- *  The form element array created for this field.
- */
-function field_default_form($entity_type, $entity, $field, $instance, $langcode, $items, &$form, &$form_state, $get_delta = NULL) {
-  // This could be called with no entity, as when a UI module creates a
-  // dummy form to set default values.
-  if ($entity) {
-    $id = $entity->id();
-  }
-
-  $parents = $form['#parents'];
-
-  $addition = array();
-  $field_name = $field['field_name'];
-  $addition[$field_name] = array();
-
-  // Populate widgets with default values when creating a new entity.
-  if (empty($items) && empty($id)) {
-    $items = field_get_default_value($entity_type, $entity, $field, $instance, $langcode);
-  }
-
-  // Let modules alter the widget properties.
-  $context = array(
-    'entity_type' => $entity_type,
-    'entity' => $entity,
-    'field' => $field,
-    'instance' => $instance,
-    'default' => !$entity,
-  );
-  drupal_alter(array('field_widget_properties', 'field_widget_properties_' . $entity_type), $instance['widget'], $context);
-
-  // Collect widget elements.
-  $elements = array();
-
-  // Store field information in $form_state.
-  if (!field_form_get_state($parents, $field_name, $langcode, $form_state)) {
-    $field_state = array(
-      'field' => $field,
-      'instance' => $instance,
-      'items_count' => count($items),
-      'array_parents' => array(),
-      'errors' => array(),
-    );
-    field_form_set_state($parents, $field_name, $langcode, $form_state, $field_state);
-  }
-
-  // If field module handles multiple values for this form element, and we are
-  // displaying an individual element, process the multiple value form.
-  if (!isset($get_delta) && field_behaviors_widget('multiple values', $instance) == FIELD_BEHAVIOR_DEFAULT) {
-    // Store the entity in the form.
-    $form['#entity'] = $entity;
-    $elements = field_multiple_value_form($field, $instance, $langcode, $items, $form, $form_state);
-  }
-  // If the widget is handling multiple values (e.g Options), or if we are
-  // displaying an individual element, just get a single form element and make
-  // it the $delta value.
-  else {
-    $delta = isset($get_delta) ? $get_delta : 0;
-    $function = $instance['widget']['module'] . '_field_widget_form';
-    if (function_exists($function)) {
-      $element = array(
-        '#entity_type' => $instance['entity_type'],
-        '#entity' => $entity,
-        '#bundle' => $instance['bundle'],
-        '#field_name' => $field_name,
-        '#language' => $langcode,
-        '#field_parents' => $parents,
-        '#columns' => array_keys($field['columns']),
-        '#title' => check_plain($instance['label']),
-        '#description' => field_filter_xss($instance['description']),
-        // Only the first widget should be required.
-        '#required' => $delta == 0 && $instance['required'],
-        '#delta' => $delta,
-      );
-      if ($element = $function($form, $form_state, $field, $instance, $langcode, $items, $delta, $element)) {
-        // Allow modules to alter the field widget form element.
-        $context = array(
-          'form' => $form,
-          'field' => $field,
-          'instance' => $instance,
-          'langcode' => $langcode,
-          'items' => $items,
-          'delta' => $delta,
-          'default' => !$entity,
-        );
-        drupal_alter(array('field_widget_form', 'field_widget_' . $instance['widget']['type'] . '_form'), $element, $form_state, $context);
-
-        // If we're processing a specific delta value for a field where the
-        // field module handles multiples, set the delta in the result.
-        // For fields that handle their own processing, we can't make
-        // assumptions about how the field is structured, just merge in the
-        // returned element.
-        if (field_behaviors_widget('multiple values', $instance) == FIELD_BEHAVIOR_DEFAULT) {
-          $elements[$delta] = $element;
-        }
-        else {
-          $elements = $element;
-        }
-      }
-    }
-  }
-
-  // Also aid in theming of field widgets by rendering a classified container.
-  $addition[$field_name] = array(
-    '#type' => 'container',
-    '#attributes' => array(
-      'class' => array(
-        'field-type-' . drupal_html_class($field['type']),
-        'field-name-' . drupal_html_class($field_name),
-        'field-widget-' . drupal_html_class($instance['widget']['type']),
-      ),
-    ),
-    '#weight' => $instance['widget']['weight'],
-  );
-
-  // Populate the 'array_parents' information in $form_state['field'] after
-  // the form is built, so that we catch changes in the form structure performed
-  // in alter() hooks.
-  $elements['#after_build'][] = 'field_form_element_after_build';
-  $elements['#field_name'] = $field_name;
-  $elements['#language'] = $langcode;
-  $elements['#field_parents'] = $parents;
-
-  $addition[$field_name] += array(
-    '#tree' => TRUE,
-    // The '#language' key can be used to access the field's form element
-    // when $langcode is unknown.
-    '#language' => $langcode,
-    $langcode => $elements,
-    '#access' => field_access('edit', $field, $entity_type, $entity),
-  );
-
-  return $addition;
-}
-
-/**
- * Special handling to create form elements for multiple values.
- *
- * Handles generic features for multiple fields:
- * - number of widgets
- * - AHAH-'add more' button
- * - drag-n-drop value reordering
- */
-function field_multiple_value_form($field, $instance, $langcode, $items, &$form, &$form_state) {
-  $field_name = $field['field_name'];
-  $parents = $form['#parents'];
-
-  // Determine the number of widgets to display.
-  switch ($field['cardinality']) {
-    case FIELD_CARDINALITY_UNLIMITED:
-      $field_state = field_form_get_state($parents, $field_name, $langcode, $form_state);
-      $max = $field_state['items_count'];
-      break;
-
-    default:
-      $max = $field['cardinality'] - 1;
-      break;
-  }
-
-  $title = check_plain($instance['label']);
-  $description = field_filter_xss($instance['description']);
-
-  $id_prefix = implode('-', array_merge($parents, array($field_name)));
-  $wrapper_id = drupal_html_id($id_prefix . '-add-more-wrapper');
-
-  $field_elements = array();
-
-  $function = $instance['widget']['module'] . '_field_widget_form';
-  if (function_exists($function)) {
-    for ($delta = 0; $delta <= $max; $delta++) {
-      $multiple = $field['cardinality'] > 1 || $field['cardinality'] == FIELD_CARDINALITY_UNLIMITED;
-      $element = array(
-        '#entity_type' => $instance['entity_type'],
-        '#entity' => $form['#entity'],
-        '#bundle' => $instance['bundle'],
-        '#field_name' => $field_name,
-        '#language' => $langcode,
-        '#field_parents' => $parents,
-        '#columns' => array_keys($field['columns']),
-        // For multiple fields, title and description are handled by the wrapping table.
-        '#title' => $multiple ? '' : $title,
-        '#description' => $multiple ? '' : $description,
-        // Only the first widget should be required.
-        '#required' => $delta == 0 && $instance['required'],
-        '#delta' => $delta,
-        '#weight' => $delta,
-      );
-      if ($element = $function($form, $form_state, $field, $instance, $langcode, $items, $delta, $element)) {
-        // Input field for the delta (drag-n-drop reordering).
-        if ($multiple) {
-          // We name the element '_weight' to avoid clashing with elements
-          // defined by widget.
-          $element['_weight'] = array(
-            '#type' => 'weight',
-            '#title' => t('Weight for row @number', array('@number' => $delta + 1)),
-            '#title_display' => 'invisible',
-             // Note: this 'delta' is the FAPI 'weight' element's property.
-            '#delta' => $max,
-            '#default_value' => isset($items[$delta]['_weight']) ? $items[$delta]['_weight'] : $delta,
-            '#weight' => 100,
-          );
-        }
-
-        // Allow modules to alter the field widget form element.
-        $context = array(
-          'form' => $form,
-          'field' => $field,
-          'instance' => $instance,
-          'langcode' => $langcode,
-          'items' => $items,
-          'delta' => $delta,
-          'default' => FALSE,
-        );
-        drupal_alter(array('field_widget_form', 'field_widget_' . $instance['widget']['type'] . '_form'), $element, $form_state, $context);
-
-        $field_elements[$delta] = $element;
-      }
-    }
-
-    if ($field_elements) {
-      $field_elements += array(
-        '#theme' => 'field_multiple_value_form',
-        '#field_name' => $field['field_name'],
-        '#cardinality' => $field['cardinality'],
-        '#title' => $title,
-        '#required' => $instance['required'],
-        '#description' => $description,
-        '#prefix' => '<div id="' . $wrapper_id . '">',
-        '#suffix' => '</div>',
-        '#max_delta' => $max,
-      );
-      // Add 'add more' button, if not working with a programmed form.
-      if ($field['cardinality'] == FIELD_CARDINALITY_UNLIMITED && empty($form_state['programmed'])) {
-        $field_elements['add_more'] = array(
-          '#type' => 'submit',
-          '#name' => strtr($id_prefix, '-', '_') . '_add_more',
-          '#value' => t('Add another item'),
-          '#attributes' => array('class' => array('field-add-more-submit')),
-          '#limit_validation_errors' => array(array_merge($parents, array($field_name, $langcode))),
-          '#submit' => array('field_add_more_submit'),
-          '#ajax' => array(
-            'callback' => 'field_add_more_js',
-            'wrapper' => $wrapper_id,
-            'effect' => 'fade',
-          ),
-        );
-      }
-    }
-  }
-
-  return $field_elements;
-}
-
-/**
  * Returns HTML for an individual form element.
  *
  * Combine multiple values into a table with drag-n-drop reordering.
@@ -387,43 +103,6 @@ function field_form_element_after_build($element, &$form_state) {
 }
 
 /**
- * Transfer field-level validation errors to widgets.
- */
-function field_default_form_errors($entity_type, $entity, $field, $instance, $langcode, $items, $form, &$form_state) {
-  $field_state = field_form_get_state($form['#parents'], $field['field_name'], $langcode, $form_state);
-
-  if (!empty($field_state['errors'])) {
-    // Locate the correct element in the form.
-    $element = drupal_array_get_nested_value($form_state['complete_form'], $field_state['array_parents']);
-    // Only set errors if the element is accessible.
-    if (!isset($element['#access']) || $element['#access']) {
-      $function = $instance['widget']['module'] . '_field_widget_error';
-      $function_exists = function_exists($function);
-
-      $multiple_widget = field_behaviors_widget('multiple values', $instance) != FIELD_BEHAVIOR_DEFAULT;
-      foreach ($field_state['errors'] as $delta => $delta_errors) {
-        // For multiple single-value widgets, pass errors by delta.
-        // For a multiple-value widget, pass all errors to the main widget.
-        $error_element = $multiple_widget ? $element : $element[$delta];
-        foreach ($delta_errors as $error) {
-          if ($function_exists) {
-            $function($error_element, $error, $form, $form_state);
-          }
-          else {
-            // Make sure that errors are reported (even incorrectly flagged) if
-            // the widget module fails to implement hook_field_widget_error().
-            form_error($error_element, $error['message']);
-          }
-        }
-      }
-      // Reinitialize the errors list for the next submit.
-      $field_state['errors'] = array();
-      field_form_set_state($form['#parents'], $field['field_name'], $langcode, $form_state, $field_state);
-    }
-  }
-}
-
-/**
  * Submit handler for the "Add another item" button of a field form.
  *
  * This handler is run regardless of whether JS is enabled or not. It makes
diff --git a/core/modules/field/field.info.inc b/core/modules/field/field.info.inc
index 8853126..782e5c5 100644
--- a/core/modules/field/field.info.inc
+++ b/core/modules/field/field.info.inc
@@ -5,6 +5,8 @@
  * Field Info API, providing information about available fields and field types.
  */
 
+use Drupal\field\Field\FieldInstance;
+
 /**
  * @defgroup field_info Field Info API
  * @{
@@ -88,7 +90,6 @@ function _field_info_collate_types() {
     else {
       $info = array(
         'field types' => array(),
-        'widget types' => array(),
         'formatter types' => array(),
         'storage types' => array(),
       );
@@ -108,20 +109,6 @@ function _field_info_collate_types() {
       }
       drupal_alter('field_info', $info['field types']);
 
-      // Populate widget types.
-      foreach (module_implements('field_widget_info') as $module) {
-        $widget_types = (array) module_invoke($module, 'field_widget_info');
-        foreach ($widget_types as $name => $widget_info) {
-          // Provide defaults.
-          $widget_info += array(
-            'settings' => array(),
-          );
-          $info['widget types'][$name] = $widget_info;
-          $info['widget types'][$name]['module'] = $module;
-        }
-      }
-      drupal_alter('field_widget_info', $info['widget types']);
-
       // Populate formatter types.
       foreach (module_implements('field_formatter_info') as $module) {
         $formatter_types = (array) module_invoke($module, 'field_formatter_info');
@@ -226,7 +213,7 @@ function _field_info_collate_fields() {
       foreach ($definitions['instances'] as $instance) {
         $field = $info['fields'][$instance['field_id']];
         $instance = _field_info_prepare_instance($instance, $field);
-        $info['instances'][$instance['entity_type']][$instance['bundle']][$instance['field_name']] = $instance;
+        $info['instances'][$instance['entity_type']][$instance['bundle']][$instance['field_name']] = new FieldInstance($instance);
         // Enrich field definitions with the list of bundles where they have
         // instances. NOTE: Deleted fields in $info['field_ids'] are not
         // enriched because all of their instances are deleted, too, and
@@ -506,15 +493,11 @@ function field_info_field_types($field_type = NULL) {
  *   by widget type name.
  */
 function field_info_widget_types($widget_type = NULL) {
-  $info = _field_info_collate_types();
-  $widget_types = $info['widget types'];
   if ($widget_type) {
-    if (isset($widget_types[$widget_type])) {
-      return $widget_types[$widget_type];
-    }
+    return field_get_plugin_manager('widget')->getDefinition($widget_type);
   }
   else {
-    return $widget_types;
+    return field_get_plugin_manager('widget')->getDefinitions();
   }
 }
 
diff --git a/core/modules/field/field.module b/core/modules/field/field.module
index 8157971..f7e00fa 100644
--- a/core/modules/field/field.module
+++ b/core/modules/field/field.module
@@ -489,6 +489,35 @@ function field_associate_fields($module) {
 }
 
 /**
+ * Returns the PluginManager object
+ *
+ * @param $plugin_type
+ *   The plugin type. One of:
+ *   - field_type
+ *   - widget
+ *   - formatter
+ *   - storage
+ *
+ * @return Drupal\Component\Plugin\PluginManagerInterface
+ *   The PluginManager object.
+ */
+function field_get_plugin_manager($plugin_type) {
+  $plugin_types = drupal_static(__FUNCTION__, array());
+
+  $classes = array(
+    'widget' => 'Drupal\field\Plugin\WidgetPluginManager',
+  );
+
+  if (isset($classes[$plugin_type])) {
+    if (empty($plugin_types[$plugin_type])) {
+      $plugin_types[$plugin_type] = new $classes[$plugin_type]();
+    }
+
+    return $plugin_types[$plugin_type];
+  }
+}
+
+/**
  * Helper function to get the default value for a field on an entity.
  *
  * @param $entity_type
@@ -897,7 +926,8 @@ function field_view_field($entity_type, $entity, $field_name, $display = array()
   if ($field = field_info_field($field_name)) {
     if (is_array($display)) {
       // When using custom display settings, fill in default values.
-      $display = _field_info_prepare_instance_display($field, $display);
+      $cache = _field_info_field_cache();
+      $display = $cache->prepareInstanceDisplay($display, $field["type"]);
     }
 
     // Hook invocations are done through the _field_invoke() functions in
diff --git a/core/modules/field/lib/Drupal/field/Field/FieldInstance.php b/core/modules/field/lib/Drupal/field/Field/FieldInstance.php
new file mode 100644
index 0000000..81b2b7d
--- /dev/null
+++ b/core/modules/field/lib/Drupal/field/Field/FieldInstance.php
@@ -0,0 +1,100 @@
+<?php
+
+/**
+ * Definition of Drupal\field\Field\FieldInstance.
+ */
+
+namespace Drupal\field\Field;
+use Drupal\field\Field\Widget\WidgetInterface;
+
+use ArrayAccess;
+
+/**
+ * Class for field instance objects.
+ */
+class FieldInstance implements ArrayAccess {
+
+  public $definition;
+
+  /**
+   * @var Drupal\field\Field\Widget\WidgetInterface
+   */
+  protected $widget;
+
+  public function __construct($definition) {
+    $this->definition = $definition;
+  }
+
+  /**
+   * @todo
+   *
+   * @return Drupal\field\Field\Widget\WidgetInterface
+   */
+  public function getWidget() {
+    if (empty($this->widget)) {
+      $widget_config = $this->definition['widget'];
+      $options = array(
+        'instance' => $this,
+        'type' => $widget_config['type'],
+        'settings' => $widget_config['settings'],
+        'weight' => $widget_config['weight'],
+      );
+      $this->widget = field_get_plugin_manager('widget')->getInstance($options);
+    }
+
+    return $this->widget;
+  }
+
+  /**
+   * Implements ArrayAccess::offsetExists().
+   */
+  public function offsetExists($offset) {
+    return isset($this->definition[$offset]) || array_key_exists($offset, $this->definition);
+  }
+
+  /**
+   * Implements ArrayAccess::offsetGet().
+   *
+   * @todo the 'return by reference' part is needed for code like
+   * $instance['settings']['foo'] = 'bar' to work.
+   * But only works for PHP >= 5.3.4, and thus chokes on the testbot currently.
+   */
+  public function &offsetGet($offset) {
+    return $this->definition[$offset];
+  }
+
+  /**
+   * Implements ArrayAccess::offsetSet().
+   */
+  public function offsetSet($offset, $value) {
+    if (!isset($offset)) {
+      // Do nothing; $array[] syntax is not supported by this temporary wrapper.
+      return;
+    }
+    $this->definition[$offset] = $value;
+
+    // If the widget properties changed, the widget plugin needs to be
+    // re-instanciated.
+    if ($offset == 'widget') {
+      unset($this->widget);
+    }
+  }
+
+  /**
+   * Implements ArrayAccess::offsetUnset().
+   */
+  public function offsetUnset($offset) {
+    unset($this->definition[$offset]);
+
+    // If the widget properties changed, the widget plugin needs to be
+    // re-instanciated.
+    if ($offset == 'widget') {
+      unset($this->widget);
+    }
+  }
+
+  public function getArray() {
+    return $this->definition;
+  }
+
+}
\ No newline at end of file
diff --git a/core/modules/field/lib/Drupal/field/Field/PluginSettingsBase.php b/core/modules/field/lib/Drupal/field/Field/PluginSettingsBase.php
new file mode 100644
index 0000000..05f2d85
--- /dev/null
+++ b/core/modules/field/lib/Drupal/field/Field/PluginSettingsBase.php
@@ -0,0 +1,77 @@
+<?php
+
+/**
+ * @file
+ *
+ * Definition of Drupal\field\Field\PluginSettingsBase.
+ */
+
+namespace Drupal\field\Field;
+use Drupal\Component\Plugin\PluginBase;
+use Drupal\field\Field\PluginSettingsInterface;
+
+/**
+ * Base class various Field API plugins.
+ */
+abstract class PluginSettingsBase extends PluginBase implements PluginSettingsInterface {
+
+  protected $settings = array();
+
+  protected $defaultSettingsMerged = FALSE;
+
+  /**
+   * Implements Drupal\field\Field\PluginSettingsInterface::getSettings().
+   */
+  public function getSettings() {
+    // Merge defaults before returning the array.
+    if (!$this->defaultSettingsMerged) {
+      $this->mergeDefaults();
+    }
+    return $this->settings;
+  }
+
+  /**
+   * Implements Drupal\field\Field\PluginSettingsInterface::getSetting().
+   */
+  public function getSetting($key) {
+    // Merge defaults if we have no value for the key.
+    if (!$this->defaultSettingsMerged && !array_key_exists($key, $this->settings)) {
+      $this->mergeDefaults();
+    }
+    return isset($this->settings[$key]) ? $this->settings[$key] : NULL;
+  }
+
+  /**
+   * Merges default settings values.
+   */
+  protected function mergeDefaults() {
+    $this->settings += $this->getDefaultSettings();
+    $this->defaultSettingsMerged = TRUE;
+  }
+
+  /**
+   * Implements Drupal\field\Field\PluginSettingsInterface::getDefaultSettings().
+   */
+  public function getDefaultSettings() {
+    $definition = $this->getDefinition();
+    return $definition['settings'];
+  }
+
+  /**
+   * Implements Drupal\field\Field\PluginSettingsInterface::setSettings().
+   */
+  public function setSettings(array $settings) {
+    $this->settings = $settings;
+    $this->defaultSettingsMerged = FALSE;
+    return $this;
+  }
+
+  /**
+   * Implements Drupal\field\Field\PluginSettingsInterface::setSetting().
+   */
+  public function setSetting($key, $value) {
+    $this->settings[$key] = $value;
+    return $this;
+  }
+
+}
diff --git a/core/modules/field/lib/Drupal/field/Field/PluginSettingsInterface.php b/core/modules/field/lib/Drupal/field/Field/PluginSettingsInterface.php
new file mode 100644
index 0000000..aeb41c1
--- /dev/null
+++ b/core/modules/field/lib/Drupal/field/Field/PluginSettingsInterface.php
@@ -0,0 +1,69 @@
+<?php
+
+/**
+ * @file
+ *
+ * Definition of Drupal\field\Field\Widget\PluginSettingsInterface.
+ */
+
+namespace Drupal\field\Field;
+use Drupal\Component\Plugin\PluginInspectionInterface;
+
+/**
+ * Interface definition for plugin with settings.
+ */
+interface PluginSettingsInterface extends PluginInspectionInterface {
+
+  /**
+   * Returns the array of settings, including defaults for missing settings.
+   *
+   * @return
+   *   The array of settings.
+   */
+  public function getSettings();
+
+  /**
+   * Returns the value of a setting, or the default value if absent.
+   *
+   * @param $key
+   *   The setting name
+   *
+   * @return
+   *   The setting value.
+   */
+  public function getSetting($key);
+
+  /**
+   * Returns the default settings for the Plugin.
+   *
+   * @return
+   *   The array of default setting values, keyed by setting names.
+   */
+  public function getDefaultSettings();
+
+  /**
+   * Sets the settings for the Plugin.
+   *
+   * @param $ŝettings
+   *   The array of settings, keyed by setting names. Missing settings will be
+   *   assigned their default values.
+   *
+   * @return PluginSettingsBase
+   *   The Plugin itself.
+   */
+  public function setSettings(array $settings);
+
+  /**
+   * Sets the value of a setting for the Plugin.
+   *
+   * @param $key
+   *   The setting name.
+   * @param $value
+   *   The setting value.
+   *
+   * @return PluginSettingsBase
+   *   The Plugin itself.
+   */
+  public function setSetting($key, $value);
+
+}
diff --git a/core/modules/field/lib/Drupal/field/Field/Widget/LegacyWidget.php b/core/modules/field/lib/Drupal/field/Field/Widget/LegacyWidget.php
new file mode 100644
index 0000000..a706dbe
--- /dev/null
+++ b/core/modules/field/lib/Drupal/field/Field/Widget/LegacyWidget.php
@@ -0,0 +1,73 @@
+<?php
+
+/**
+ * @file
+ *
+ * Definition of Drupal\field\Field\Widget\LegacyWidget.
+ */
+
+namespace Drupal\field\Field\Widget;
+
+use Drupal\field\Field\Widget\WidgetBase;
+use Drupal\entity\EntityInterface;
+
+/**
+ * Plugin implementation for legacy widgets.
+ * This contains all widgets that still need to be converted to the new widget system.
+ */
+class LegacyWidget extends WidgetBase {
+
+  /**
+   * Implements Drupal\field\Field\Widget\WidgetInterface::formElement().
+   */
+  public function formElement(array $items, $delta, array $element, $langcode, array &$form, array &$form_state) {
+    $definition = $this->getDefinition();
+    $function = $definition['module'] . '_field_widget_form';
+    return $function($form, $form_state, $this->field, $this->instance, $langcode, $items, $delta, $element);
+  }
+
+  /**
+   * Overrides Drupal\field\Field\Widget\WidgetBase::flagErrors().
+   *
+   * In D7, hook_field_widget_error() was supposed to call form_error() itself,
+   * whereas the new errorElement() method simply returns the element to flag.
+   * So we override the flagError() method to be more similar to the previous
+   * code in field_default_form_errors().
+   */
+  public function flagErrors(EntityInterface $entity, $langcode, array $items, array $form, array &$form_state) {
+    $field_name = $this->field['field_name'];
+
+    $field_state = field_form_get_state($form['#parents'], $field_name, $langcode, $form_state);
+
+    if (!empty($field_state['errors'])) {
+      // Locate the correct element in the form.
+      $element = drupal_array_get_nested_value($form_state['complete_form'], $field_state['array_parents']);
+      // Only set errors if the element is accessible.
+      if (!isset($element['#access']) || $element['#access']) {
+        $definition = $this->getDefinition();
+        $is_multiple = $definition['multiple_values'];
+        $function = $definition['module'] . '_field_widget_error';
+        $function_exists = function_exists($function);
+
+        foreach ($field_state['errors'] as $delta => $delta_errors) {
+          // For multiple single-value widgets, pass errors by delta.
+          // For a multiple-value widget, pass all errors to the main widget.
+          $error_element = $is_multiple ? $element : $element[$delta];
+          foreach ($delta_errors as $error) {
+            if ($function_exists) {
+              $function($error_element, $error, $form, $form_state);
+            }
+            else {
+              // Make sure that errors are reported (even incorrectly flagged) if
+              // the widget module fails to implement hook_field_widget_error().
+              form_error($error_element, $error['message']);
+            }
+          }
+        }
+        // Reinitialize the errors list for the next submit.
+        $field_state['errors'] = array();
+        field_form_set_state($form['#parents'], $field['field_name'], $langcode, $form_state, $field_state);
+      }
+    }
+  }
+}
diff --git a/core/modules/field/lib/Drupal/field/Field/Widget/WidgetBase.php b/core/modules/field/lib/Drupal/field/Field/Widget/WidgetBase.php
new file mode 100644
index 0000000..1132023
--- /dev/null
+++ b/core/modules/field/lib/Drupal/field/Field/Widget/WidgetBase.php
@@ -0,0 +1,419 @@
+<?php
+
+/**
+ * @file
+ *
+ * Definition of Drupal\field\Field\Widget\WidgetBase.
+ */
+
+namespace Drupal\field\Field\Widget;
+
+use Drupal\field\Field\PluginSettingsBase;
+use Drupal\field\Field\FieldInstance;
+use Drupal\entity\EntityInterface;
+use Drupal\Component\Plugin\Discovery\DiscoveryInterface;
+
+/**
+ * Base class for 'Field widget' plugin implementations.
+ */
+abstract class WidgetBase extends PluginSettingsBase implements WidgetInterface {
+
+  protected $field;
+
+  protected $instance;
+
+  public function __construct($plugin_id, DiscoveryInterface $discovery, $instance, array $settings, $weight) {
+    parent::__construct(array(), $plugin_id, $discovery);
+
+    $this->instance = $instance;
+    $this->field = field_info_field($instance['field_name']);
+    $this->settings = $settings;
+    $this->weight = $weight;
+  }
+
+  /**
+   * Implements \Drupal\field\Field\Widget\WidgetInterface::form().
+   */
+  public function form(EntityInterface $entity, $langcode, array $items, array &$form, array &$form_state, $get_delta = NULL) {
+    $entity_type = $entity->entityType();
+    $field = $this->field;
+    $instance = $this->instance;
+    $field_name = $field['field_name'];
+
+    $parents = $form['#parents'];
+
+    $addition = array(
+      $field_name => array(),
+    );
+
+    // Populate widgets with default values when creating a new entity.
+    if (empty($items) && ($entity->isNew())) {
+      $items = field_get_default_value($entity_type, $entity, $field, $instance, $langcode);
+    }
+
+    // Let modules alter the widget properties.
+    $context = array(
+      'entity_type' => $entity_type,
+      'entity' => $entity,
+      'field' => $field,
+      'instance' => $instance,
+      'default' => $entity->isNew(),
+    );
+    drupal_alter(array('field_widget_properties', 'field_widget_properties_' . $entity_type), $this, $context);
+
+    // Store field information in $form_state.
+    if (!field_form_get_state($parents, $field_name, $langcode, $form_state)) {
+      $field_state = array(
+          'field' => $field,
+          'instance' => $instance,
+          'items_count' => count($items),
+          'array_parents' => array(),
+          'errors' => array(),
+      );
+      field_form_set_state($parents, $field_name, $langcode, $form_state, $field_state);
+    }
+
+    // Collect widget elements.
+    $elements = array();
+
+    // If the widget is handling multiple values (e.g Options), or if we are
+    // displaying an individual element, just get a single form element and make
+    // it the $delta value.
+    // @todo get rid of $get_delta ?
+    $definition = $this->getDefinition();
+    if (isset($get_delta) || $definition['multiple_values']) {
+      $delta = isset($get_delta) ? $get_delta : 0;
+      $element = array(
+        '#title' => check_plain($instance['label']),
+        '#description' => field_filter_xss($instance['description']),
+      );
+      $element = $this->formSingleElement($entity, $items, $delta, $langcode, $element, $form, $form_state);
+
+      if ($element) {
+        if (isset($get_delta)) {
+          // If we are processing a specific delta value for a field where the
+          // field module handles multiples, set the delta in the result.
+          $elements[$delta] = $element;
+        }
+        else {
+          // For fields that handle their own processing, we cannot make
+          // assumptions about how the field is structured, just merge in the
+          // returned element.
+          $elements = $element;
+        }
+      }
+    }
+    // If the widget does not handle multiple values itself, (and we are not
+    // displaying an individual element), process the multiple value form.
+    else {
+      $elements = $this->formMultipleElements($entity, $items, $langcode, $form, $form_state);
+    }
+
+    // Also aid in theming of field widgets by rendering a classified
+    // container.
+    $addition[$field_name] = array(
+      '#type' => 'container',
+      '#attributes' => array(
+        'class' => array(
+          'field-type-' . drupal_html_class($field['type']),
+          'field-name-' . drupal_html_class($field_name),
+          'field-widget-' . drupal_html_class($this->getPluginId()),
+        ),
+      ),
+      '#weight' => $this->weight,
+    );
+
+    // Populate the 'array_parents' information in $form_state['field'] after
+    // the form is built, so that we catch changes in the form structure performed
+    // in alter() hooks.
+    $elements['#after_build'][] = 'field_form_element_after_build';
+    $elements['#field_name'] = $field_name;
+    $elements['#language'] = $langcode;
+    $elements['#field_parents'] = $parents;
+
+    $addition[$field_name] += array(
+      '#tree' => TRUE,
+      // The '#language' key can be used to access the field's form element
+      // when $langcode is unknown.
+      '#language' => $langcode,
+      $langcode => $elements,
+      '#access' => field_access('edit', $field, $entity_type, $entity),
+    );
+
+    return $addition;
+  }
+
+  /**
+   * Special handling to create form elements for multiple values.
+   *
+   * Handles generic features for multiple fields:
+   * - number of widgets
+   * - AHAH-'add more' button
+   * - table display and drag-n-drop value reordering
+   */
+  protected function formMultipleElements(EntityInterface $entity, array $items, $langcode, array &$form, array &$form_state) {
+    $field = $this->field;
+    $instance = $this->instance;
+    $field_name = $field['field_name'];
+
+    $parents = $form['#parents'];
+
+    // Determine the number of widgets to display.
+    switch ($field['cardinality']) {
+      case FIELD_CARDINALITY_UNLIMITED:
+        $field_state = field_form_get_state($parents, $field_name, $langcode, $form_state);
+        $max = $field_state['items_count'];
+        $is_multiple = TRUE;
+        break;
+
+      default:
+        $max = $field['cardinality'] - 1;
+        $is_multiple = ($field['cardinality'] > 1);
+        break;
+    }
+
+    $id_prefix = implode('-', array_merge($parents, array($field_name)));
+    $wrapper_id = drupal_html_id($id_prefix . '-add-more-wrapper');
+
+    $title = check_plain($instance['label']);
+    $description = field_filter_xss($instance['description']);
+
+    $elements = array();
+
+    for ($delta = 0; $delta <= $max; $delta++) {
+      // For multiple fields, title and description are handled by the wrapping
+      // table.
+      $element = array(
+        '#title' => $is_multiple ? '' : $title,
+        '#description' => $is_multiple ? '' : $description,
+      );
+      $element = $this->formSingleElement($entity, $items, $delta, $langcode, $element, $form, $form_state);
+
+      if ($element) {
+        // Input field for the delta (drag-n-drop reordering).
+        if ($is_multiple) {
+          // We name the element '_weight' to avoid clashing with elements
+          // defined by widget.
+          $element['_weight'] = array(
+            '#type' => 'weight',
+            '#title' => t('Weight for row @number', array('@number' => $delta + 1)),
+            '#title_display' => 'invisible',
+            // Note: this 'delta' is the FAPI #type 'weight' element's property.
+            '#delta' => $max,
+            '#default_value' => isset($items[$delta]['_weight']) ? $items[$delta]['_weight'] : $delta,
+            '#weight' => 100,
+          );
+        }
+
+        $elements[$delta] = $element;
+      }
+    }
+
+    if ($elements) {
+      $elements += array(
+        '#theme' => 'field_multiple_value_form',
+        '#field_name' => $field['field_name'],
+        '#cardinality' => $field['cardinality'],
+        '#required' => $instance['required'],
+        '#title' => $title,
+        '#description' => $description,
+        '#prefix' => '<div id="' . $wrapper_id . '">',
+        '#suffix' => '</div>',
+        '#max_delta' => $max,
+      );
+
+      // Add 'add more' button, if not working with a programmed form.
+      if ($field['cardinality'] == FIELD_CARDINALITY_UNLIMITED && empty($form_state['programmed'])) {
+        $elements['add_more'] = array(
+          '#type' => 'submit',
+          '#name' => strtr($id_prefix, '-', '_') . '_add_more',
+          '#value' => t('Add another item'),
+          '#attributes' => array('class' => array('field-add-more-submit')),
+          '#limit_validation_errors' => array(array_merge($parents, array($field_name, $langcode))),
+          '#submit' => array('field_add_more_submit'),
+          '#ajax' => array(
+              'callback' => 'field_add_more_js',
+              'wrapper' => $wrapper_id,
+              'effect' => 'fade',
+          ),
+        );
+      }
+    }
+
+    return $elements;
+  }
+
+  /**
+   * @todo
+   */
+  protected function formSingleElement(EntityInterface $entity, array $items, $delta, $langcode, array $element, array &$form, array &$form_state) {
+    $instance = $this->instance;
+    $field = $this->field;
+
+    $element += array(
+      '#entity_type' => $instance['entity_type'],
+      '#bundle' => $instance['bundle'],
+      '#entity' => $entity,
+      '#field_name' => $field['field_name'],
+      '#language' => $langcode,
+      '#field_parents' => $form['#parents'],
+      '#columns' => array_keys($field['columns']),
+      // Only the first widget should be required.
+      '#required' => $delta == 0 && $instance['required'],
+      '#delta' => $delta,
+      '#weight' => $delta,
+    );
+
+    $element = $this->formElement($items, $delta, $element, $langcode, $form, $form_state);
+
+    if ($element) {
+      // Allow modules to alter the field widget form element.
+      $context = array(
+        'form' => $form,
+        'instance' => $instance,
+        'langcode' => $langcode,
+        'items' => $items,
+        'delta' => $delta,
+        'default' => empty($entity),
+      );
+      drupal_alter(array('field_widget_form', 'field_widget_' . $this->getPluginId() . '_form'), $element, $form_state, $context);
+    }
+
+    return $element;
+  }
+
+  /**
+   * Implements \Drupal\field\Field\Widget\WidgetInterface::flagErrors().
+   */
+  public function flagErrors(EntityInterface $entity, $langcode, array $items, array $form, array &$form_state) {
+    $field_name = $this->field['field_name'];
+
+    $field_state = field_form_get_state($form['#parents'], $field_name, $langcode, $form_state);
+
+    if (!empty($field_state['errors'])) {
+      // Locate the correct element in the the form.
+      $element = drupal_array_get_nested_value($form_state['complete_form'], $field_state['array_parents']);
+
+      // Only set errors if the element is accessible.
+      if (!isset($element['#access']) || $element['#access']) {
+        $definition = $this->getDefinition();
+        $is_multiple = $definition['multiple_values'];
+
+        foreach ($field_state['errors'] as $delta => $delta_errors) {
+          // For single-value widgets, pass errors by delta.
+          // For a multiple-value widget, pass all errors to the main widget.
+          $delta_element = $is_multiple ? $element : $element[$delta];
+          foreach ($delta_errors as $error) {
+            $error_element = $this->errorElement($delta_element, $error, $form, $form_state);
+            form_error($error_element, $error['message']);
+          }
+        }
+        // Reinitialize the errors list for the next submit.
+        $field_state['errors'] = array();
+        field_form_set_state($form['#parents'], $field_name, $langcode, $form_state, $field_state);
+      }
+    }
+  }
+
+  /**
+   * Implements \Drupal\field\Field\Widget\WidgetInterface::extractFormValues().
+   */
+  public function extractFormValues(EntityInterface $entity, $langcode, array &$items, array $form, array &$form_state) {
+    $field_name = $this->field['field_name'];
+
+    $items = array();
+
+    // Extract the values from $form_state['values'].
+    $path = array_merge($form['#parents'], array($field_name, $langcode));
+    $key_exists = NULL;
+    $values = drupal_array_get_nested_value($form_state['values'], $path, $key_exists);
+
+    if ($key_exists) {
+      // Remove the 'value' of the 'add more' button.
+      unset($values['add_more']);
+
+      // Let the widget turn the submitted values into actual field values.
+      // 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'];
+        }
+      }
+      $items = $this->fieldValuesFromFormValues($values, $form, $form_state);
+      if ($weights) {
+        foreach ($items as $delta => $item) {
+          $items[$delta]['_weight'] = $weights[$delta];
+        }
+      }
+    }
+
+    // Save the extracted $items in $form_state, so that we do not have to
+    // compute them again in submit().
+    // @todo Why don't we just use form_set_value() ?
+    $field_state = field_form_get_state($form['#parents'], $field_name, $langcode, $form_state);
+    $field_state['items'] = $items;
+    field_form_set_state($form['#parents'], $field_name, $langcode, $form_state, $field_state);
+  }
+
+  /**
+   * Implements \Drupal\field\Field\Widget\WidgetInterface::submit().
+   */
+  public function submit(EntityInterface $entity, $langcode, array &$items, array $form, array &$form_state) {
+    $field_name = $this->field['field_name'];
+
+    // Get the $items saved in $form_state during extractFormValues().
+    $field_state = field_form_get_state($form['#parents'], $field_name, $langcode, $form_state);
+    $items = $field_state['items'];
+
+    // Remove empty values.
+    $items = _field_filter_items($this->field, $items);
+
+    // Account for drag-n-drop reordering.
+    $this->sortItems($items);
+  }
+
+  /**
+   * Sorts submitted field values according to drag-n-drop reordering.
+   *
+   * @param $items
+   *   The field values.
+   */
+  protected function sortItems(array &$items) {
+    $is_multiple = ($this->field['cardinality'] == FIELD_CARDINALITY_UNLIMITED) || ($this->field['cardinality'] > 1);
+    if ($is_multiple && isset($items[0]['_weight'])) {
+      usort($items, function ($a, $b) {
+        $a_weight = (is_array($a) ? $a['_weight'] : 0);
+        $b_weight = (is_array($b) ? $b['_weight'] : 0);
+        return $a_weight - $b_weight;
+      });
+      // Remove the '_weight' entires.
+      foreach ($items as $delta => &$item) {
+        if (is_array($item)) {
+          unset($item['_weight']);
+        }
+      }
+    }
+  }
+
+  /**
+   * Implements WidgetInterface::settingsForm().
+   */
+  public function settingsForm(array $form, array &$form_state) {
+    return array();
+  }
+
+  /**
+   * Implements WidgetInterface::errorElement().
+   */
+  public function errorElement(array $element, array $error, array $form, array &$form_state) {
+    return $element;
+  }
+
+  /**
+   * Implements WidgetInterface::fieldValuesFromFormValues()
+   */
+  public function fieldValuesFromFormValues($values, $form, &$form_state) {
+    return $values;
+  }
+}
diff --git a/core/modules/field/lib/Drupal/field/Field/Widget/WidgetBaseInterface.php b/core/modules/field/lib/Drupal/field/Field/Widget/WidgetBaseInterface.php
new file mode 100644
index 0000000..9ee2009
--- /dev/null
+++ b/core/modules/field/lib/Drupal/field/Field/Widget/WidgetBaseInterface.php
@@ -0,0 +1,100 @@
+<?php
+
+/**
+ * @file
+ *
+ * Definition of Drupal\field\Field\Widget\WidgetInterface.
+ */
+
+namespace Drupal\field\Field\Widget;
+use Drupal\entity\EntityInterface;
+use Drupal\field\Field\PluginSettingsInterface;
+
+/**
+ * Interface definition for "Field widget" plugins.
+ */
+interface WidgetBaseInterface extends PluginSettingsInterface {
+
+  /**
+   * Creates a form element for a field.
+   *
+   * If the entity associated with the form is new (i.e., $entity->isNew() is
+   * TRUE), the 'default value', if any, is pre-populated. Also allows other
+   * modules to alter the form element by implementing their own hooks.
+   *
+   * @param Drupal\entity\EntityInterface $entity
+   *   The entity object that the field belongs to. This may be NULL if creating
+   *   a form element with a default value.
+   * @param $langcode
+   *   The language associated with the field.
+   * @param $items
+   *   An array of the field values. When creating a new entity this may be NULL
+   *   or an empty array to use default values.
+   * @param $form
+   *   An array representing the form that the editing element will be attached
+   *   to.
+   * @param $form_state
+   *   An array containing the current state of the form.
+   * @param $get_delta
+   *   Used to get only a specific delta value of a multiple value field.
+   *
+   * @return
+   *  The form element array created for this field.
+   */
+  public function form(EntityInterface $entity, $langcode, array $items, array &$form, array &$form_state, $get_delta = NULL);
+
+  /**
+   * Extracts field values from submitted form values.
+   *
+   * @param $entity
+   *   The entity for the operation.
+   * @param $langcode
+   *   The language associated to $items.
+   * @param $items
+   *   The field values. This parameter is altered by reference to receive the
+   *   incoming form values.
+   * @param $form
+   *   The form structure where field elements are attached to. This might be a
+   *   full form structure, or a sub-element of a larger form.
+   * @param $form_state
+   *   The form state.
+   */
+  public function extractFormValues(EntityInterface $entity, $langcode, array &$items, array $form, array &$form_state);
+
+  /**
+   * Reports field-level validation errors against actual form elements.
+   *
+   * @param Drupal\entity\EntityInterface $entity
+   *   The entity for the operation.
+   * @param $langcode
+   *   The language associated to $items.
+   * @param $items
+   *   The field values.
+   * @param $form
+   *   The form structure where field elements are attached to. This might be a
+   *   full form structure, or a sub-element of a larger form.
+   * @param $form_state
+   *   The form state.
+   */
+  public function flagErrors(EntityInterface $entity, $langcode, array $items, array $form, array &$form_state);
+
+  /**
+   * Massages submitted values before they are assigned to the $entity.
+   *
+   * @param $entity
+   *   The entity for the operation.
+   * @param $langcode
+   *   The language associated to $items.
+   * @param $items
+   *   The field values. This parameter is altered by reference to receive the
+   *   incoming form values.
+   * @param $form
+   *   The form structure where field elements are attached to. This might be a
+   *   full form structure, or a sub-element of a larger form.
+   * @param $form_state
+   *   The form state.
+   *
+   * @todo merge with extractFormValues() ?
+   */
+  public function submit(EntityInterface $entity, $langcode, array &$items, array $form, array &$form_state);
+}
diff --git a/core/modules/field/lib/Drupal/field/Field/Widget/WidgetInterface.php b/core/modules/field/lib/Drupal/field/Field/Widget/WidgetInterface.php
new file mode 100644
index 0000000..1c681d2
--- /dev/null
+++ b/core/modules/field/lib/Drupal/field/Field/Widget/WidgetInterface.php
@@ -0,0 +1,158 @@
+<?php
+
+/**
+ * @file
+ *
+ * Definition of Drupal\field\Field\Widget\WidgetInterface.
+ */
+
+namespace Drupal\field\Field\Widget;
+use Drupal\field\Field\FieldInstance;
+use Drupal\entity\EntityInterface;
+
+/**
+ * Interface definition for "Field widget" plugins.
+ */
+interface WidgetInterface extends WidgetBaseInterface {
+
+  /**
+   * Returns a form to configure settings for the widget.
+   *
+   * Invoked from field_ui_field_edit_form() to allow administrators to
+   * configure the widget. The field_ui module takes care of handling submitted
+   * form values.
+   * .
+   * @param $form
+   *   The form where the settings form is being included in.
+   * @param $form_state
+   *   An associative array containing the current state of the form.
+   *
+   * @return
+   *   The form definition for the widget settings.
+   */
+  public function settingsForm(array $form, array &$form_state);
+
+  /**
+   * Returns the form for a single field widget.
+   *
+   * Field widget form elements should be based on the passed-in $element, which
+   * contains the base form element properties derived from the field
+   * configuration.
+   *
+   * The BaseWidget methods will set the weight, field name and delta values for
+   * each form element. If there are multiple values for this field, the
+   * formElement() method will be called as many times as needed.
+   *
+   * Note that, depending on the context in which the widget is being included
+   * (regular entity form, field configuration form, advanced search form...),
+   * the values for $field and $instance might be different from the "official"
+   * definitions returned by field_info_field() and field_info_instance().
+   * Examples: mono-value widget even if the field is multi-valued, non-required
+   * widget even if the field is 'required'...
+   *
+   * Therefore, the FAPI element callbacks (such as #process, #element_validate,
+   * #value_callback...) used by the widget cannot use the field_info_field()
+   * or field_info_instance() functions to retrieve the $field or $instance
+   * definitions they should operate on. The field_widget_field() and
+   * field_widget_instance() functions should be used instead to fetch the
+   * current working definitions from $form_state, where Field API stores them.
+   *
+   * Alternatively, hook_field_widget_form() can extract the needed specific
+   * properties from $field and $instance and set them as ad-hoc
+   * $element['#custom'] properties, for later use by its element callbacks.
+   *
+   * Other modules may alter the form element provided by this function using
+   * hook_field_widget_form_alter().
+   *
+   * @param $items
+   *   Array of default values for this field.
+   * @param $delta
+   *   The order of this item in the array of subelements (0, 1, 2, etc).
+   * @param $element
+   *   A form element array containing basic properties for the widget:
+   *   - #entity_type: The name of the entity the field is attached to.
+   *   - #bundle: The name of the field bundle the field is contained in.
+   *   - #entity: The entity the field is attached to.
+   *   - #field_name: The name of the field.
+   *   - #language: The language the field is being edited in.
+   *   - #field_parents: The 'parents' space for the field in the form. Most
+   *       widgets can simply overlook this property. This identifies the
+   *       location where the field values are placed within
+   *       $form_state['values'], and is used to access processing information
+   *       for the field through the field_form_get_state() and
+   *       field_form_set_state() functions.
+   *   - #columns: A list of field storage columns of the field.
+   *   - #title: The sanitized element label for the field instance, ready for
+   *     output.
+   *   - #description: The sanitized element description for the field instance,
+   *     ready for output.
+   *   - #required: A Boolean indicating whether the element value is required;
+   *     for required multiple value fields, only the first widget's values are
+   *     required.
+   *   - #delta: The order of this item in the array of subelements; see $delta
+   *     above.
+   * @param $langcode
+   *   The language associated with $items.
+   * @param $form
+   *   The form structure where widgets are being attached to. This might be a
+   *   full form structure, or a sub-element of a larger form.
+   * @param $form_state
+   *   An associative array containing the current state of the form.
+   *
+   * @return
+   *   The form elements for a single widget for this field.
+   *
+   * @see field_widget_field()
+   * @see field_widget_instance()
+   * @see hook_field_widget_form_alter()
+   * @see hook_field_widget_WIDGET_TYPE_form_alter()
+   */
+  public function formElement(array $items, $delta, array $element, $langcode, array &$form, array &$form_state);
+
+  /**
+   * Assigns a field-level validation error to the right widget sub-element.
+   *
+   * Depending on the widget's internal structure, a field-level validation
+   * error needs to be flagged on the right sub-element.
+   *
+   * @param $element
+   *   An array containing the form element for the widget, as generated by
+   *   formElement().
+   * @param $error
+   *   An associative array with the following key-value pairs, as returned by
+   *   hook_field_validate():
+   *   - error: the error code. Complex widgets might need to report different
+   *     errors to different form elements inside the widget.
+   *   - message: the human readable message to be displayed.
+   * @param $form
+   *   The form structure where field elements are attached to. This might be a
+   *   full form structure, or a sub-element of a larger form.
+   * @param $form_state
+   *   An associative array containing the current state of the form.
+   *
+   * @return
+   *   The element on which the error should be flagged.
+   */
+  public function errorElement(array $element, array $error, array $form, array &$form_state);
+
+  /**
+   * Massages the form values into the format expected for field values.
+   *
+   * @param $values
+   *   The submitted form values produced by the widget.
+   *   - If the widget does not manage multiple values itself, the array holds
+   *     the values generated by the multiple copies of the $element generated
+   *     by the formElement() method, keyed by delta.
+   *   - If the widget manages multiple values, the array holds the values
+   *     of the form element generated by the formElement() method.
+   * @param $form
+   *   The form structure where field elements are attached to. This might be a
+   *   full form structure, or a sub-element of a larger form.
+   * @param $form_state
+   *   The form state.
+   *
+   * @return
+   *   An array of field values, keyed by delta.
+   */
+  public function fieldValuesFromFormValues($values, $form, &$form_state);
+}
diff --git a/core/modules/field/lib/Drupal/field/Plugin/WidgetPluginManager.php b/core/modules/field/lib/Drupal/field/Plugin/WidgetPluginManager.php
new file mode 100644
index 0000000..9459bc2
--- /dev/null
+++ b/core/modules/field/lib/Drupal/field/Plugin/WidgetPluginManager.php
@@ -0,0 +1,87 @@
+<?php
+
+/**
+ * @file
+ *
+ * Definition of Drupal\field\Plugin\WidgetPluginManager.
+ */
+
+namespace Drupal\field\Plugin;
+use Drupal\Component\Plugin\PluginManagerBase;
+use Drupal\Core\Plugin\Discovery\CacheDecorator;
+use Drupal\Core\Plugin\Discovery\HookDiscovery;
+use Drupal\Component\Plugin\Factory\ReflectionFactory;
+
+/**
+ * 'Field widget' plugin type manager.
+ */
+class WidgetPluginManager extends PluginManagerBase {
+
+  protected $defaults = array(
+    'settings' => array(),
+    'multiple_values' => FALSE,
+    'class' => 'Drupal\field\Field\Widget\LegacyWidget',
+  );
+
+  protected $cache_bin = 'field';
+  protected $cache_key = 'field_widget_types';
+  protected $hook = 'field_widget_info';
+
+  public function __construct() {
+    $this->discovery = new CacheDecorator(new HookDiscovery($this->hook), $this->cache_key, $this->cache_bin);
+    $this->factory = new ReflectionFactory($this);
+  }
+
+  /**
+   * Clear cached definitions.
+   * @todo A cleaner way should be baked within CacheDecorator.
+   */
+  public function clearDefinitions() {
+    // Clear 'static' data by creating a new object.
+    $this->discovery = new CacheDecorator(new HookDiscovery($this->hook), $this->cache_key, $this->cache_bin);
+    cache($this->cache_bin)->delete($this->cache_key);
+  }
+
+ /**
+   * Overrides PluginManagerBase::getInstance().
+   * @todo This takes the place of a Mapper - Do we want a real Mapper instead ?
+   */
+  public function getInstance(array $options) {
+    $instance = $options['instance'];
+    $type = $options['type'];
+
+    $definition = $this->getDefinition($type);
+    $field = field_info_field($instance['field_name']);
+
+    // Switch back to default widget if either:
+    // - $type_info doesn't exist (the widget type is unknown),
+    // - the field type is not allowed for the widget.
+    if (!isset($definition['class']) || !in_array($field['type'], $definition['field types'])) {
+      // Grab the default widget for the field type.
+      $field_type_definition = field_info_field_types($field['type']);
+      $type = $field_type_definition['default_widget'];
+    }
+
+    $configuration = array(
+      'instance' => $instance,
+      'settings' => $options['settings'],
+      'weight' => $options['weight'],
+    );
+
+    return $this->createInstance($type, $configuration);
+  }
+
+  /**
+   * Overrides PluginManagerBase::processDefinition().
+   */
+  protected function processDefinition(&$definition, $plugin_id) {
+    parent::processDefinition($definition, $plugin_id);
+
+    // Temporary BC layer : transform properties for which the format has
+    // changed.
+    if (isset($definition['behaviors']['multiple values'])) {
+      $definition['multiple_values'] = $definition['behaviors']['multiple values'];
+      unset($definition['behaviors']['multiple values']);
+    }
+  }
+}
diff --git a/core/modules/field/modules/number/lib/Drupal/number/Field/Widget/NumberWidget.php b/core/modules/field/modules/number/lib/Drupal/number/Field/Widget/NumberWidget.php
new file mode 100644
index 0000000..81f3834
--- /dev/null
+++ b/core/modules/field/modules/number/lib/Drupal/number/Field/Widget/NumberWidget.php
@@ -0,0 +1,69 @@
+<?php
+
+/**
+ * @file
+ *
+ * Definition of Drupal\text\Field\Widget\TextareaWidget.
+ */
+
+namespace Drupal\number\Field\Widget;
+use Drupal\field\Field\Widget\WidgetBase;
+
+/**
+ * Plugin implementation of the 'number' widget.
+ */
+class NumberWidget extends WidgetBase {
+
+  /**
+   * Implements WidgetInterface::formElement().
+   */
+  public function formElement(array $items, $delta, array $element, $langcode, array &$form, array &$form_state) {
+    $field = $this->field;
+    $instance = $this->instance;
+
+    $value = isset($items[$delta]['value']) ? $items[$delta]['value'] : NULL;
+
+    $element += array(
+      '#type' => 'number',
+      '#default_value' => $value,
+    );
+
+    // Set the step for floating point and decimal numbers.
+    switch ($field['type']) {
+      case 'number_decimal':
+        $element['#step'] = pow(0.1, $field['settings']['scale']);
+        break;
+
+      case 'number_float':
+        $element['#step'] = 'any';
+        break;
+    }
+
+    // Set minimum and maximum.
+    if (is_numeric($instance['settings']['min'])) {
+      $element['#min'] = $instance['settings']['min'];
+    }
+    if (is_numeric($instance['settings']['max'])) {
+      $element['#max'] = $instance['settings']['max'];
+    }
+
+    // Add prefix and suffix.
+    if (!empty($instance['settings']['prefix'])) {
+      $prefixes = explode('|', $instance['settings']['prefix']);
+      $element['#field_prefix'] = field_filter_xss(array_pop($prefixes));
+    }
+    if (!empty($instance['settings']['suffix'])) {
+      $suffixes = explode('|', $instance['settings']['suffix']);
+      $element['#field_suffix'] = field_filter_xss(array_pop($suffixes));
+    }
+
+    return array('value' => $element);
+  }
+
+  /**
+   * Implements WidgetInterface::errorElement().
+   */
+  public function errorElement(array $element, array $error, array $form, array &$form_state) {
+    return $element['value'];
+  }
+}
diff --git a/core/modules/field/modules/number/number.module b/core/modules/field/modules/number/number.module
index 9985984..a0d3ede 100644
--- a/core/modules/field/modules/number/number.module
+++ b/core/modules/field/modules/number/number.module
@@ -49,6 +49,32 @@ function number_field_info() {
 }
 
 /**
+ * Implements hook_field_widget_info().
+ */
+/*function number_field_widget_info() {
+  return array(
+    'number' => array(
+      'label' => t('Text field'),
+      'field types' => array('number_integer', 'number_decimal', 'number_float'),
+    ),
+  );
+}*/
+
+/**
+ * Implements hook_field_widget_info().
+ */
+function number_field_widget_info() {
+  return array(
+    'number' => array(
+      'label' => t('Text field'),
+      'class' => '\Drupal\number\Field\Widget\NumberWidget',
+      'field types' => array('number_integer', 'number_decimal', 'number_float'),
+      'settings' => array(),
+    ),
+  );
+}
+
+/**
  * Implements hook_field_settings_form().
  */
 function number_field_settings_form($field, $instance, $has_data) {
@@ -304,65 +330,3 @@ function number_field_formatter_view($entity_type, $entity, $field, $instance, $
 
   return $element;
 }
-
-/**
- * Implements hook_field_widget_info().
- */
-function number_field_widget_info() {
-  return array(
-    'number' => array(
-      'label' => t('Text field'),
-      'field types' => array('number_integer', 'number_decimal', 'number_float'),
-    ),
-  );
-}
-
-/**
- * Implements hook_field_widget_form().
- */
-function number_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) {
-  $value = isset($items[$delta]['value']) ? $items[$delta]['value'] : '';
-
-  $element += array(
-    '#type' => 'number',
-    '#default_value' => $value,
-  );
-
-  // Set the step for floating point and decimal numbers.
-  switch ($field['type']) {
-    case 'number_decimal':
-      $element['#step'] = pow(0.1, $field['settings']['scale']);
-      break;
-
-    case 'number_float':
-      $element['#step'] = 'any';
-      break;
-  }
-
-  // Set minimum and maximum.
-  if (is_numeric($instance['settings']['min'])) {
-    $element['#min'] = $instance['settings']['min'];
-  }
-  if (is_numeric($instance['settings']['max'])) {
-    $element['#max'] = $instance['settings']['max'];
-  }
-
-  // Add prefix and suffix.
-  if (!empty($instance['settings']['prefix'])) {
-    $prefixes = explode('|', $instance['settings']['prefix']);
-    $element['#field_prefix'] = field_filter_xss(array_pop($prefixes));
-  }
-  if (!empty($instance['settings']['suffix'])) {
-    $suffixes = explode('|', $instance['settings']['suffix']);
-    $element['#field_suffix'] = field_filter_xss(array_pop($suffixes));
-  }
-
-  return array('value' => $element);
-}
-
-/**
- * Implements hook_field_widget_error().
- */
-function number_field_widget_error($element, $error, $form, &$form_state) {
-  form_error($element['value'], $error['message']);
-}
diff --git a/core/modules/field/modules/text/lib/Drupal/text/Field/Widget/TextareaWidget.php b/core/modules/field/modules/text/lib/Drupal/text/Field/Widget/TextareaWidget.php
new file mode 100644
index 0000000..a8f60b5
--- /dev/null
+++ b/core/modules/field/modules/text/lib/Drupal/text/Field/Widget/TextareaWidget.php
@@ -0,0 +1,57 @@
+<?php
+
+/**
+ * @file
+ *
+ * Definition of Drupal\text\Field\Widget\TextareaWidget.
+ */
+
+namespace Drupal\text\Field\Widget;
+use Drupal\field\Field\Widget\WidgetBase;
+
+/**
+ * Plugin implementation of the 'text_textarea' widget.
+ */
+class TextareaWidget extends WidgetBase {
+
+  /**
+   * Implements WidgetInterface::settingsForm().
+   */
+  public function settingsForm(array $form, array &$form_state) {
+    $element = array();
+
+    $element['rows'] = array(
+      '#type' => 'number',
+      '#title' => t('Rows'),
+      '#default_value' => $this->getSetting('rows'),
+      '#required' => TRUE,
+      '#min' => 1,
+    );
+
+    return $element;
+  }
+
+  /**
+   * Implements WidgetInterface::formElement().
+   */
+  public function formElement(array $items, $delta, array $element, $langcode, array &$form, array &$form_state) {
+    $main_widget = $element + array(
+      '#type' => 'textarea',
+      '#default_value' => isset($items[$delta]['value']) ? $items[$delta]['value'] : NULL,
+      '#rows' => $this->getSetting('rows'),
+      '#attributes' => array('class' => array('text-full')),
+    );
+
+    if ($this->instance['settings']['text_processing']) {
+      $element = $main_widget;
+      $element['#type'] = 'text_format';
+      $element['#format'] = isset($items[$delta]['format']) ? $items[$delta]['format'] : NULL;
+      $element['#base_type'] = $main_widget['#type'];
+    }
+    else {
+      $element['value'] = $main_widget;
+    }
+
+    return $element;
+  }
+}
diff --git a/core/modules/field/modules/text/lib/Drupal/text/Field/Widget/TextareaWithSummaryWidget.php b/core/modules/field/modules/text/lib/Drupal/text/Field/Widget/TextareaWithSummaryWidget.php
new file mode 100644
index 0000000..4cc8882
--- /dev/null
+++ b/core/modules/field/modules/text/lib/Drupal/text/Field/Widget/TextareaWithSummaryWidget.php
@@ -0,0 +1,57 @@
+<?php
+
+/**
+ * @file
+ *
+ * Definition of Drupal\text\Field\Widget\TextareaWithSummaryWidget.
+ */
+
+namespace Drupal\text\Field\Widget;
+
+/**
+ * Plugin implementation of the 'text_textarea_with_summary' widget.
+ */
+class TextareaWithSummaryWidget extends TextareaWidget {
+
+  /**
+   * Overrides TextareaWidget::formElement().
+   */
+  function formElement(array $items, $delta, array $element, $langcode, array &$form, array &$form_state) {
+    $element = parent::formElement($items, $delta, $element, $langcode, $form, $form_state);
+
+    $display_summary = !empty($items[$delta]['summary']) || $this->instance['settings']['display_summary'];
+    $element['summary'] = array(
+      '#type' => $display_summary ? 'textarea' : 'value',
+      '#default_value' => isset($items[$delta]['summary']) ? $items[$delta]['summary'] : NULL,
+      '#title' => t('Summary'),
+      '#rows' => $this->getSetting('summary_rows'),
+      '#description' => t('Leave blank to use trimmed value of full text as the summary.'),
+      '#attached' => array(
+        'js' => array(drupal_get_path('module', 'text') . '/text.js'),
+      ),
+      '#attributes' => array('class' => array('text-summary')),
+      '#prefix' => '<div class="text-summary-wrapper">',
+      '#suffix' => '</div>',
+      '#weight' => -10,
+    );
+
+    return $element;
+  }
+
+  /**
+   * Overrides TextareaWidget::errorElement().
+   */
+  public function errorElement(array $element, array $error, array $form, array &$form_state) {
+    switch ($error['error']) {
+      case 'text_summary_max_length':
+        $error_element = $element['summary'];
+        break;
+
+      default:
+        $error_element = $element;
+        break;
+    }
+
+    return $error_element;
+  }
+}
diff --git a/core/modules/field/modules/text/lib/Drupal/text/Field/Widget/TextfieldWidget.php b/core/modules/field/modules/text/lib/Drupal/text/Field/Widget/TextfieldWidget.php
new file mode 100644
index 0000000..821d2ab
--- /dev/null
+++ b/core/modules/field/modules/text/lib/Drupal/text/Field/Widget/TextfieldWidget.php
@@ -0,0 +1,58 @@
+<?php
+
+/**
+ * @file
+ *
+ * Definition of Drupal\text\Field\Widget\TextfieldWidget.
+ */
+
+namespace Drupal\text\Field\Widget;
+use Drupal\field\Field\Widget\WidgetBase;
+
+/**
+ * Plugin implementation of the 'text_textfield' widget.
+ */
+class TextfieldWidget extends WidgetBase {
+
+  /**
+   * Implements WidgetInterface::settingsForm().
+   */
+  public function settingsForm(array $form, array &$form_state) {
+    $element = array();
+
+    $element['size'] = array(
+      '#type' => 'number',
+      '#title' => t('Size of textfield'),
+      '#default_value' => $this->getSetting('size'),
+      '#required' => TRUE,
+      '#min' => 1,
+    );
+
+    return $element;
+  }
+
+  /**
+   * Implements WidgetInterface::formElement().
+   */
+  public function formElement(array $items, $delta, array $element, $langcode, array &$form, array &$form_state) {
+    $main_widget = $element + array(
+      '#type' => 'textfield',
+      '#default_value' => isset($items[$delta]['value']) ? $items[$delta]['value'] : NULL,
+      '#size' => $this->getSetting('size'),
+      '#maxlength' => $this->field['settings']['max_length'],
+      '#attributes' => array('class' => array('text-full')),
+    );
+
+    if ($this->instance['settings']['text_processing']) {
+      $element = $main_widget;
+      $element['#type'] = 'text_format';
+      $element['#format'] = isset($items[$delta]['format']) ? $items[$delta]['format'] : NULL;
+      $element['#base_type'] = $main_widget['#type'];
+    }
+    else {
+      $element['value'] = $main_widget;
+    }
+
+    return $element;
+  }
+}
diff --git a/core/modules/field/modules/text/text.module b/core/modules/field/modules/text/text.module
index dcf4d1e..918c4eb 100644
--- a/core/modules/field/modules/text/text.module
+++ b/core/modules/field/modules/text/text.module
@@ -450,16 +450,19 @@ function text_field_widget_info() {
   return array(
     'text_textfield' => array(
       'label' => t('Text field'),
+      'class' => '\Drupal\text\Field\Widget\TextfieldWidget',
       'field types' => array('text'),
       'settings' => array('size' => 60),
     ),
     'text_textarea' => array(
       'label' => t('Text area (multiple rows)'),
+      'class' => '\Drupal\text\Field\Widget\TextareaWidget',
       'field types' => array('text_long'),
       'settings' => array('rows' => 5),
     ),
     'text_textarea_with_summary' => array(
       'label' => t('Text area with a summary'),
+      'class' => '\Drupal\text\Field\Widget\TextareaWithSummaryWidget',
       'field types' => array('text_with_summary'),
       'settings' => array('rows' => 9, 'summary_rows' => 3),
     ),
@@ -467,117 +470,6 @@ function text_field_widget_info() {
 }
 
 /**
- * Implements hook_field_widget_settings_form().
- */
-function text_field_widget_settings_form($field, $instance) {
-  $widget = $instance['widget'];
-  $settings = $widget['settings'];
-
-  if ($widget['type'] == 'text_textfield') {
-    $form['size'] = array(
-      '#type' => 'number',
-      '#title' => t('Size of textfield'),
-      '#default_value' => $settings['size'],
-      '#required' => TRUE,
-      '#min' => 1,
-    );
-  }
-  else {
-    $form['rows'] = array(
-      '#type' => 'number',
-      '#title' => t('Rows'),
-      '#default_value' => $settings['rows'],
-      '#required' => TRUE,
-      '#min' => 1,
-    );
-  }
-
-  return $form;
-}
-
-/**
- * Implements hook_field_widget_form().
- */
-function text_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) {
-  $summary_widget = array();
-  $main_widget = array();
-
-  switch ($instance['widget']['type']) {
-    case 'text_textfield':
-      $main_widget = $element + array(
-        '#type' => 'textfield',
-        '#default_value' => isset($items[$delta]['value']) ? $items[$delta]['value'] : NULL,
-        '#size' => $instance['widget']['settings']['size'],
-        '#maxlength' => $field['settings']['max_length'],
-        '#attributes' => array('class' => array('text-full')),
-      );
-      break;
-
-    case 'text_textarea_with_summary':
-      $display = !empty($items[$delta]['summary']) || !empty($instance['settings']['display_summary']);
-      $summary_widget = array(
-        '#type' => $display ? 'textarea' : 'value',
-        '#default_value' => isset($items[$delta]['summary']) ? $items[$delta]['summary'] : NULL,
-        '#title' => t('Summary'),
-        '#rows' => $instance['widget']['settings']['summary_rows'],
-        '#description' => t('Leave blank to use trimmed value of full text as the summary.'),
-        '#attached' => array(
-          'js' => array(drupal_get_path('module', 'text') . '/text.js'),
-        ),
-        '#attributes' => array('class' => array('text-summary')),
-        '#prefix' => '<div class="text-summary-wrapper">',
-        '#suffix' => '</div>',
-        '#weight' => -10,
-      );
-      // Fall through to the next case.
-
-    case 'text_textarea':
-      $main_widget = $element + array(
-        '#type' => 'textarea',
-        '#default_value' => isset($items[$delta]['value']) ? $items[$delta]['value'] : NULL,
-        '#rows' => $instance['widget']['settings']['rows'],
-        '#attributes' => array('class' => array('text-full')),
-      );
-      break;
-  }
-
-  if ($main_widget) {
-    // Conditionally alter the form element's type if text processing is enabled.
-    if ($instance['settings']['text_processing']) {
-      $element = $main_widget;
-      $element['#type'] = 'text_format';
-      $element['#format'] = isset($items[$delta]['format']) ? $items[$delta]['format'] : NULL;
-      $element['#base_type'] = $main_widget['#type'];
-    }
-    else {
-      $element['value'] = $main_widget;
-    }
-  }
-  if ($summary_widget) {
-    $element['summary'] = $summary_widget;
-  }
-
-  return $element;
-}
-
-/**
- * Implements hook_field_widget_error().
- */
-function text_field_widget_error($element, $error, $form, &$form_state) {
-  switch ($error['error']) {
-    case 'text_summary_max_length':
-      $error_element = $element[$element['#columns'][1]];
-      break;
-
-    default:
-      $error_element = $element[$element['#columns'][0]];
-      break;
-  }
-
-  form_error($error_element, $error['message']);
-}
-
-/**
  * Implements hook_field_prepare_translation().
  */
 function text_field_prepare_translation($entity_type, $entity, $field, $instance, $langcode, &$items, $source_entity, $source_langcode) {
diff --git a/core/modules/field_ui/field_ui.admin.inc b/core/modules/field_ui/field_ui.admin.inc
index 5871be0..0193348 100644
--- a/core/modules/field_ui/field_ui.admin.inc
+++ b/core/modules/field_ui/field_ui.admin.inc
@@ -1,5 +1,7 @@
 <?php
 
+use Drupal\field\Field\FieldInterface;
+
 /**
  * @file
  * Administrative interface for custom field type creation.
@@ -307,7 +309,6 @@ function field_ui_field_overview_form($form, &$form_state, $entity_type, $bundle
   // Gather bundle information.
   $instances = field_info_instances($entity_type, $bundle);
   $field_types = field_info_field_types();
-  $widget_types = field_info_widget_types();
 
   $extra_fields = field_info_extra_fields($entity_type, $bundle, 'form');
 
@@ -345,6 +346,8 @@ function field_ui_field_overview_form($form, &$form_state, $entity_type, $bundle
   foreach ($instances as $name => $instance) {
     $field = field_info_field($instance['field_name']);
     $admin_field_path = $admin_path . '/fields/' . $instance['field_name'];
+    $widget_definition = $instance->getWidget()->getDefinition();
+
     $table[$name] = array(
       '#attributes' => array('class' => array('draggable', 'tabledrag-leaf')),
       '#row_type' => 'field',
@@ -387,7 +390,7 @@ function field_ui_field_overview_form($form, &$form_state, $entity_type, $bundle
       ),
       'widget_type' => array(
         '#type' => 'link',
-        '#title' => t($widget_types[$instance['widget']['type']]['label']),
+        '#title' => $widget_definition['label'],
         '#href' => $admin_field_path . '/widget-type',
         '#options' => array('attributes' => array('title' => t('Change widget type.'))),
       ),
@@ -1656,7 +1659,7 @@ function field_ui_field_settings_form_submit($form, &$form_state) {
  * @see field_ui_widget_type_form_submit()
  * @ingroup forms
  */
-function field_ui_widget_type_form($form, &$form_state, $instance) {
+function field_ui_widget_type_form($form, &$form_state, FieldInstance $instance) {
   drupal_set_title($instance['label']);
 
   $bundle = $instance['bundle'];
@@ -1665,7 +1668,7 @@ function field_ui_widget_type_form($form, &$form_state, $instance) {
 
   $field = field_info_field($field_name);
   $field_type = field_info_field_types($field['type']);
-  $widget_type = field_info_widget_types($instance['widget']['type']);
+  $widget_definition = $instance->getWidget()->getDefinition();
   $bundles = field_info_bundles();
   $bundle_label = $bundles[$entity_type][$bundle]['label'];
 
@@ -1684,7 +1687,7 @@ function field_ui_widget_type_form($form, &$form_state, $instance) {
     '#title' => t('Widget type'),
     '#required' => TRUE,
     '#options' => field_ui_widget_type_options($field['type']),
-    '#default_value' => $instance['widget']['type'],
+    '#default_value' => $instance->getWidget()->getPluginId(),
     '#description' => t('The type of form element you would like to present to the user when creating this field in the %type type.', array('%type' => $bundle_label)),
   );
 
@@ -1816,6 +1819,9 @@ function field_ui_field_edit_form($form, &$form_state, $instance) {
 
   $form['#field'] = $field;
   $form['#instance'] = $instance;
+  // Create an arbitrary entity object (used by the 'default value' widget).
+  $ids = (object) array('entity_type' => $instance['entity_type'], 'bundle' => $instance['bundle'], 'entity_id' => NULL);
+  $form['#entity'] = _field_create_entity_from_ids($ids);
 
   if (!empty($field['locked'])) {
     $form['locked'] = array(
@@ -1905,12 +1911,9 @@ function field_ui_field_edit_form($form, &$form_state, $instance) {
     $form['instance']['settings'] = $additions;
   }
 
-  // Add additional widget settings from the widget module.
-  $additions = module_invoke($widget_type['module'], 'field_widget_settings_form', $field, $instance);
-  if (is_array($additions)) {
-    $form['instance']['widget']['settings'] = $additions;
-    $form['instance']['widget']['active']['#value'] = 1;
-  }
+  // Add widget settings for the widget type.
+  $additions = $instance->getWidget()->settingsForm($form, $form_state);
+  $form['instance']['widget']['settings'] = $additions ? $additions : array('#type' => 'value', '#value' => array());
 
   // Add handling for default value if not provided by any other module.
   if (field_behaviors_widget('default value', $instance) == FIELD_BEHAVIOR_DEFAULT && empty($instance['default_value_function'])) {
@@ -2017,6 +2020,7 @@ function field_ui_field_edit_instance_pre_render($element) {
  */
 function field_ui_default_value_widget($field, $instance, &$form, &$form_state) {
   $field_name = $field['field_name'];
+  $entity = $form['#entity'];
 
   $element = array(
     '#type' => 'fieldset',
@@ -2035,8 +2039,9 @@ function field_ui_default_value_widget($field, $instance, &$form, &$form_state)
   $instance['required'] = FALSE;
   $instance['description'] = '';
 
-  // @todo Allow multiple values (requires more work on 'add more' JS handler).
-  $element += field_default_form($instance['entity_type'], NULL, $field, $instance, LANGUAGE_NOT_SPECIFIED, $items, $element, $form_state, 0);
+  $items = (array) $items;
+  // @todo : use field_invoke_method() ?
+  $element += $instance->getWidget()->form($entity, LANGUAGE_NOT_SPECIFIED, $items, $element, $form_state);
 
   return $element;
 }
@@ -2049,8 +2054,9 @@ function field_ui_default_value_widget($field, $instance, &$form, &$form_state)
 function field_ui_field_edit_form_validate($form, &$form_state) {
   // Take the incoming values as the $instance definition, so that the 'default
   // value' gets validated using the instance settings being submitted.
-  $instance = $form_state['values']['instance'];
+  $instance = $form['#instance'];
   $field_name = $instance['field_name'];
+  $entity = $form['#entity'];
 
   if (isset($form['instance']['default_value_widget'])) {
     $element = $form['instance']['default_value_widget'];
@@ -2060,7 +2066,8 @@ function field_ui_field_edit_form_validate($form, &$form_state) {
 
     // Extract the 'default value'.
     $items = array();
-    field_default_extract_form_values(NULL, NULL, $field, $instance, LANGUAGE_NOT_SPECIFIED, $items, $element, $form_state);
+    // @todo : use field_invoke_method() ?
+    $instance->getWidget()->extractFormValues($entity, LANGUAGE_NOT_SPECIFIED, $items, $element, $form_state);
 
     // Validate the value and report errors.
     $errors = array();
@@ -2073,7 +2080,8 @@ function field_ui_field_edit_form_validate($form, &$form_state) {
       $field_state['errors'] = $errors[$field_name][LANGUAGE_NOT_SPECIFIED];
       field_form_set_state($element['#parents'], $field_name, LANGUAGE_NOT_SPECIFIED, $form_state, $field_state);
       // Assign reported errors to the correct form element.
-      field_default_form_errors(NULL, NULL, $field, $instance, LANGUAGE_NOT_SPECIFIED, $items, $element, $form_state);
+      // @todo : use field_invoke_method() ?
+      $instance->getWidget()->flagErrors($entity, LANGUAGE_NOT_SPECIFIED, $items, $element, $form_state);
     }
   }
 }
@@ -2084,12 +2092,12 @@ function field_ui_field_edit_form_validate($form, &$form_state) {
  * @see field_ui_field_edit_form_validate().
  */
 function field_ui_field_edit_form_submit($form, &$form_state) {
-  $instance = $form_state['values']['instance'];
-  $field = $form_state['values']['field'];
+  $instance = $form['#instance'];
+  $field = $form['#field'];
+  $entity = $form['#entity'];
 
-  // Update any field settings that have changed.
-  $field_source = field_info_field($instance['field_name']);
-  $field = array_merge($field_source, $field);
+  // Merge incoming values into the field.
+  $field = array_merge($field, $form_state['values']['field']);
   try {
     field_update_field($field);
   }
@@ -2103,16 +2111,18 @@ function field_ui_field_edit_form_submit($form, &$form_state) {
     $element = $form['instance']['default_value_widget'];
 
     // Extract field values.
+    // @todo : use field_invoke_method() ?
     $items = array();
-    field_default_extract_form_values(NULL, NULL, $field, $instance, LANGUAGE_NOT_SPECIFIED, $items, $element, $form_state);
-    field_default_submit(NULL, NULL, $field, $instance, LANGUAGE_NOT_SPECIFIED, $items, $element, $form_state);
+    $instance->getWidget()->extractFormValues($entity, LANGUAGE_NOT_SPECIFIED, $items, $element, $form_state);
+    $instance->getWidget()->submit($entity, LANGUAGE_NOT_SPECIFIED, $items, $element, $form_state);
 
     $instance['default_value'] = $items ? $items : NULL;
   }
 
-  // Retrieve the stored instance settings to merge with the incoming values.
-  $instance_source = field_read_instance($instance['entity_type'], $instance['field_name'], $instance['bundle']);
-  $instance = array_merge($instance_source, $instance);
+  // Merge incoming values into the instance.
+  foreach ($form_state['values']['instance'] as $key => $value) {
+    $instance[$key] = $value;
+  }
   field_update_instance($instance);
 
   drupal_set_message(t('Saved %label configuration.', array('%label' => $instance['label'])));
diff --git a/core/modules/field_ui/field_ui.api.php b/core/modules/field_ui/field_ui.api.php
index 80cbe78..e33fbdd 100644
--- a/core/modules/field_ui/field_ui.api.php
+++ b/core/modules/field_ui/field_ui.api.php
@@ -91,47 +91,6 @@ function hook_field_instance_settings_form($field, $instance) {
 }
 
 /**
- * Add settings to a widget settings form.
- *
- * Invoked from field_ui_field_edit_form() to allow the module defining the
- * widget to add settings for a widget instance.
- *
- * @param $field
- *   The field structure being configured.
- * @param $instance
- *   The instance structure being configured.
- *
- * @return
- *   The form definition for the widget settings.
- */
-function hook_field_widget_settings_form($field, $instance) {
-  $widget = $instance['widget'];
-  $settings = $widget['settings'];
-
-  if ($widget['type'] == 'text_textfield') {
-    $form['size'] = array(
-      '#type' => 'number',
-      '#title' => t('Size of textfield'),
-      '#default_value' => $settings['size'],
-      '#min' => 1,
-      '#required' => TRUE,
-    );
-  }
-  else {
-    $form['rows'] = array(
-      '#type' => 'number',
-      '#title' => t('Rows'),
-      '#default_value' => $settings['rows'],
-      '#min' => 1,
-      '#required' => TRUE,
-    );
-  }
-
-  return $form;
-}
-
-
-/**
  * Specify the form elements for a formatter's settings.
  *
  * @param $field
diff --git a/core/modules/field_ui/lib/Drupal/field_ui/Tests/ManageFieldsTest.php b/core/modules/field_ui/lib/Drupal/field_ui/Tests/ManageFieldsTest.php
index 4aa0dd6..d086cb5 100644
--- a/core/modules/field_ui/lib/Drupal/field_ui/Tests/ManageFieldsTest.php
+++ b/core/modules/field_ui/lib/Drupal/field_ui/Tests/ManageFieldsTest.php
@@ -172,7 +172,7 @@ class ManageFieldsTest extends FieldUiTestBase {
    */
   function assertFieldSettings($bundle, $field_name, $string = 'dummy test string', $entity_type = 'node') {
     // Reset the fields info.
-    _field_info_collate_fields_reset();
+    field_info_cache_clear();
     // Assert field settings.
     $field = field_info_field($field_name);
     $this->assertTrue($field['settings']['test_field_setting'] == $string, t('Field settings were found.'));
@@ -262,7 +262,7 @@ class ManageFieldsTest extends FieldUiTestBase {
     $this->fieldUIDeleteField($bundle_path1, $this->field_name, $this->field_label, $this->type);
 
     // Reset the fields info.
-    _field_info_collate_fields_reset();
+    field_info_cache_clear();
     // Check that the field instance was deleted.
     $this->assertNull(field_info_instance('node', $this->field_name, $this->type), t('Field instance was deleted.'));
     // Check that the field was not deleted
@@ -272,7 +272,7 @@ class ManageFieldsTest extends FieldUiTestBase {
     $this->fieldUIDeleteField($bundle_path2, $this->field_name, $this->field_label, $type_name2);
 
     // Reset the fields info.
-    _field_info_collate_fields_reset();
+    field_info_cache_clear();
     // Check that the field instance was deleted.
     $this->assertNull(field_info_instance('node', $this->field_name, $type_name2), t('Field instance was deleted.'));
     // Check that the field was deleted too.
