diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/EmailDefaultWidget.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/EmailDefaultWidget.php
index c273bd8..faca922 100644
--- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/EmailDefaultWidget.php
+++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/EmailDefaultWidget.php
@@ -8,7 +8,7 @@
 namespace Drupal\Core\Field\Plugin\Field\FieldWidget;
 
 use Drupal\Core\Field\FieldItemListInterface;
-use Drupal\Core\Field\WidgetBase;
+use Drupal\Core\Field\WidgetBaseSingle;
 
 /**
  * Plugin implementation of the 'email_default' widget.
@@ -24,7 +24,7 @@
  *   }
  * )
  */
-class EmailDefaultWidget extends WidgetBase {
+class EmailDefaultWidget extends WidgetBaseSingle {
 
   /**
    * {@inheritdoc}
diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/NumberWidget.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/NumberWidget.php
index 82c8d37..0433cef 100644
--- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/NumberWidget.php
+++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/NumberWidget.php
@@ -8,7 +8,7 @@
 namespace Drupal\Core\Field\Plugin\Field\FieldWidget;
 
 use Drupal\Core\Field\FieldItemListInterface;
-use Drupal\Core\Field\WidgetBase;
+use Drupal\Core\Field\WidgetBaseSingle;
 use Symfony\Component\Validator\ConstraintViolationInterface;
 
 /**
@@ -27,7 +27,7 @@
  *   }
  * )
  */
-class NumberWidget extends WidgetBase {
+class NumberWidget extends WidgetBaseSingle {
 
   /**
    * {@inheritdoc}
diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/StringWidget.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/StringWidget.php
index 524e89d..f2a2664 100644
--- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/StringWidget.php
+++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/StringWidget.php
@@ -8,7 +8,7 @@
 namespace Drupal\Core\Field\Plugin\Field\FieldWidget;
 
 use Drupal\Core\Field\FieldItemListInterface;
-use Drupal\Core\Field\WidgetBase;
+use Drupal\Core\Field\WidgetBaseSingle;
 
 /**
  * Plugin implementation of the 'string' widget.
@@ -25,7 +25,7 @@
  *   }
  * )
  */
-class StringWidget extends WidgetBase {
+class StringWidget extends WidgetBaseSingle {
 
   /**
    * {@inheritdoc}
diff --git a/core/lib/Drupal/Core/Field/WidgetBase.php b/core/lib/Drupal/Core/Field/WidgetBase.php
index 6432fb1..9f6c767 100644
--- a/core/lib/Drupal/Core/Field/WidgetBase.php
+++ b/core/lib/Drupal/Core/Field/WidgetBase.php
@@ -8,7 +8,6 @@
 namespace Drupal\Core\Field;
 
 use Drupal\Component\Utility\NestedArray;
-use Drupal\Component\Utility\SortArray;
 use Drupal\Component\Utility\String;
 use Symfony\Component\Validator\ConstraintViolationInterface;
 
@@ -50,6 +49,24 @@ public function __construct($plugin_id, array $plugin_definition, FieldDefinitio
   }
 
   /**
+   * Get the form element for a single $delta.
+   */
+  protected function formDeltaElement(FieldItemListInterface $items, array &$form, array &$form_state) {
+    $delta = isset($get_delta) ? $get_delta : 0;
+    $element = array(
+      '#title' => String::checkPlain($this->fieldDefinition->getLabel()),
+      '#description' => field_filter_xss(\Drupal::token()->replace($this->fieldDefinition->getDescription())),
+    );
+    $element = $this->formSingleElement($items, $delta, $element, $form, $form_state);
+
+    if ($element) {
+      // If we are processing a specific delta value for a field where the
+      // field module handles multiples, set the delta in the result.
+      return array($delta => $element);
+    }
+  }
+
+  /**
    * {@inheritdoc}
    */
   public function form(FieldItemListInterface $items, array &$form, array &$form_state, $get_delta = NULL) {
@@ -66,37 +83,13 @@ public function form(FieldItemListInterface $items, array &$form, array &$form_s
       field_form_set_state($parents, $field_name, $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.
-    if ($this->handlesMultipleValues() || isset($get_delta)) {
-      $delta = isset($get_delta) ? $get_delta : 0;
-      $element = array(
-        '#title' => String::checkPlain($this->fieldDefinition->getLabel()),
-        '#description' => field_filter_xss(\Drupal::token()->replace($this->fieldDefinition->getDescription())),
-      );
-      $element = $this->formSingleElement($items, $delta, $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 (isset($get_delta)) {
+      // If we are displaying an individual element, just get a single form
+      // element and make it the $delta value.
+      $elements = $this->formDeltaElement($items, $form, $form_state);
     }
-    // If the widget does not handle multiple values itself, (and we are not
-    // displaying an individual element), process the multiple value form.
     else {
+      // Delegate the multiple element generation to the children classes.
       $elements = $this->formMultipleElements($items, $form, $form_state);
     }
 
@@ -129,105 +122,6 @@ public function form(FieldItemListInterface $items, array &$form, array &$form_s
   }
 
   /**
-   * 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(FieldItemListInterface $items, array &$form, array &$form_state) {
-    $field_name = $this->fieldDefinition->getName();
-    $cardinality = $this->fieldDefinition->getCardinality();
-    $parents = $form['#parents'];
-
-    // Determine the number of widgets to display.
-    switch ($cardinality) {
-      case FieldDefinitionInterface::CARDINALITY_UNLIMITED:
-        $field_state = field_form_get_state($parents, $field_name, $form_state);
-        $max = $field_state['items_count'];
-        $is_multiple = TRUE;
-        break;
-
-      default:
-        $max = $cardinality - 1;
-        $is_multiple = ($cardinality > 1);
-        break;
-    }
-
-    $id_prefix = implode('-', array_merge($parents, array($field_name)));
-    $wrapper_id = drupal_html_id($id_prefix . '-add-more-wrapper');
-
-    $title = String::checkPlain($this->fieldDefinition->getLabel());
-    $description = field_filter_xss(\Drupal::token()->replace($this->fieldDefinition->getDescription()));
-
-    $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($items, $delta, $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' => $items[$delta]->_weight ?: $delta,
-            '#weight' => 100,
-          );
-        }
-
-        $elements[$delta] = $element;
-      }
-    }
-
-    if ($elements) {
-      $elements += array(
-        '#theme' => 'field_multiple_value_form',
-        '#field_name' => $field_name,
-        '#cardinality' => $cardinality,
-        '#cardinality_multiple' => $this->fieldDefinition->isMultiple(),
-        '#required' => $this->fieldDefinition->isRequired(),
-        '#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 ($cardinality == FieldDefinitionInterface::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))),
-          '#submit' => array(array(get_class($this), 'addMoreSubmit')),
-          '#ajax' => array(
-            'callback' => array(get_class($this), 'addMoreAjax'),
-            'wrapper' => $wrapper_id,
-            'effect' => 'fade',
-          ),
-        );
-      }
-    }
-
-    return $elements;
-  }
-
-  /**
    * Submission handler for the "Add another item" button.
    */
   public static function addMoreSubmit(array $form, array &$form_state) {
@@ -271,6 +165,16 @@ public static function addMoreAjax(array $form, array $form_state) {
     return $element;
   }
 
+    /**
+     * 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
+     */
+  abstract protected function formMultipleElements(FieldItemListInterface $items, array &$form, array &$form_state);
+
   /**
    * Generates the form element for a single copy of the widget.
    */
@@ -308,6 +212,13 @@ protected function formSingleElement(FieldItemListInterface $items, $delta, arra
   }
 
   /**
+   * Massage the form values to unset 'add_more' and reorder form values.
+   *
+   * @param $values
+   */
+  protected function massageMultipleFormValues(&$values) { }
+
+  /**
    * {@inheritdoc}
    */
   public function extractFormValues(FieldItemListInterface $items, array $form, array &$form_state) {
@@ -320,20 +231,7 @@ public function extractFormValues(FieldItemListInterface $items, array $form, ar
 
     if ($key_exists) {
       // Account for drag-and-drop reordering if needed.
-      if (!$this->handlesMultipleValues()) {
-        // Remove the 'value' of the 'add more' button.
-        unset($values['add_more']);
-
-        // The original delta, before drag-and-drop reordering, is needed to
-        // route errors to the corect form element.
-        foreach ($values as $delta => &$value) {
-          $value['_original_delta'] = $delta;
-        }
-
-        usort($values, function ($a, $b) {
-          return SortArray::sortByKeyInt($a, $b, '_weight');
-        });
-      }
+      $this->massageMultipleFormValues($values);
 
       // Let the widget massage the submitted values.
       $values = $this->massageFormValues($values, $form, $form_state);
@@ -353,6 +251,19 @@ public function extractFormValues(FieldItemListInterface $items, array $form, ar
   }
 
   /**
+   * Flags the error in the appropriate form element.
+   *
+   * @param array $element
+   *   Form element containing the error.
+   * @param int $original_delta
+   *   Delta item in the form element that causes the error.
+   *
+   * @return array
+   *   Form element that gets the error flag.
+   */
+  abstract protected function deltaViolationElement(array $element, $original_delta);
+
+  /**
    * {@inheritdoc}
    */
   public function flagErrors(FieldItemListInterface $items, array $form, array &$form_state) {
@@ -381,7 +292,6 @@ public function flagErrors(FieldItemListInterface $items, array $form, array &$f
 
       // Only set errors if the element is accessible.
       if (!isset($element['#access']) || $element['#access']) {
-        $handles_multiple = $this->handlesMultipleValues();
 
         $violations_by_delta = array();
         foreach ($field_state['constraint_violations'] as $violation) {
@@ -400,13 +310,13 @@ public function flagErrors(FieldItemListInterface $items, array $form, array &$f
           // Pass violations to the main element:
           // - if this is a multiple-value widget,
           // - or if the violations are at the ItemList level.
-          if ($handles_multiple || $delta === NULL) {
+
+          if ($delta === NULL) {
             $delta_element = $element;
           }
-          // Otherwise, pass errors by delta to the corresponding sub-element.
           else {
-            $original_delta = $field_state['original_deltas'][$delta];
-            $delta_element = $element[$original_delta];
+            $original_delta = isset($field_state['original_deltas'][$delta]) ? $field_state['original_deltas'][$delta] : 0;
+            $delta_element = $this->deltaViolationElement($element, $original_delta);
           }
           foreach ($delta_violations as $violation) {
             // @todo: Pass $violation->arrayPropertyPath as property path.
@@ -474,16 +384,4 @@ protected function getFieldSetting($setting_name) {
     return $this->fieldDefinition->getSetting($setting_name);
   }
 
-  /**
-   * Returns whether the widget handles multiple values.
-   *
-   * @return bool
-   *   TRUE if a single copy of formElement() can handle multiple field values,
-   *   FALSE if multiple values require separate copies of formElement().
-   */
-  protected function handlesMultipleValues() {
-    $definition = $this->getPluginDefinition();
-    return $definition['multiple_values'];
-  }
-
 }
diff --git a/core/lib/Drupal/Core/Field/WidgetBaseMultiple.php b/core/lib/Drupal/Core/Field/WidgetBaseMultiple.php
new file mode 100644
index 0000000..d625390
--- /dev/null
+++ b/core/lib/Drupal/Core/Field/WidgetBaseMultiple.php
@@ -0,0 +1,36 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Field\WidgetBaseMultiple.
+ */
+
+namespace Drupal\Core\Field;
+
+use Drupal\Component\Utility\String;
+
+/**
+ * Base class for 'Field widget' plugin implementations.
+ */
+abstract class WidgetBaseMultiple extends WidgetBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function formMultipleElements(FieldItemListInterface $items, array &$form, array &$form_state) {
+    $element = array(
+      '#title' => String::checkPlain($this->fieldDefinition->getLabel()),
+      '#description' => field_filter_xss(\Drupal::token()->replace($this->fieldDefinition->getDescription())),
+    );
+
+    return $this->formSingleElement($items, 0, $element, $form, $form_state);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function deltaViolationElement(array $element, $original_delta) {
+    return $element;
+  }
+
+}
diff --git a/core/lib/Drupal/Core/Field/WidgetBaseSingle.php b/core/lib/Drupal/Core/Field/WidgetBaseSingle.php
new file mode 100644
index 0000000..2461628
--- /dev/null
+++ b/core/lib/Drupal/Core/Field/WidgetBaseSingle.php
@@ -0,0 +1,182 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Field\WidgetBaseSingle.
+ */
+
+namespace Drupal\Core\Field;
+
+use Drupal\Component\Utility\NestedArray;
+use Drupal\Component\Utility\SortArray;
+use Drupal\Component\Utility\String;
+
+/**
+ * Base class for 'Field widget' plugin implementations.
+ */
+abstract class WidgetBaseSingle extends WidgetBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function formMultipleElements(FieldItemListInterface $items, array &$form, array &$form_state) {
+    $field_name = $this->fieldDefinition->getName();
+    $cardinality = $this->fieldDefinition->getCardinality();
+    $parents = $form['#parents'];
+
+    // Determine the number of widgets to display.
+    switch ($cardinality) {
+      case FieldDefinitionInterface::CARDINALITY_UNLIMITED:
+        $field_state = field_form_get_state($parents, $field_name, $form_state);
+        $max = $field_state['items_count'];
+        $is_multiple = TRUE;
+        break;
+
+      default:
+        $max = $cardinality - 1;
+        $is_multiple = ($cardinality > 1);
+        break;
+    }
+
+    $id_prefix = implode('-', array_merge($parents, array($field_name)));
+    $wrapper_id = drupal_html_id($id_prefix . '-add-more-wrapper');
+
+    $title = String::checkPlain($this->fieldDefinition->getLabel());
+    $description = field_filter_xss(\Drupal::token()->replace($this->fieldDefinition->getDescription()));
+
+    $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($items, $delta, $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' => $items[$delta]->_weight ?: $delta,
+            '#weight' => 100,
+          );
+        }
+
+        $elements[$delta] = $element;
+      }
+    }
+
+    if ($elements) {
+      $elements += array(
+        '#theme' => 'field_multiple_value_form',
+        '#field_name' => $field_name,
+        '#cardinality' => $cardinality,
+        '#cardinality_multiple' => $this->fieldDefinition->isMultiple(),
+        '#required' => $this->fieldDefinition->isRequired(),
+        '#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 ($cardinality == FieldDefinitionInterface::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))),
+          '#submit' => array(array(get_class($this), 'addMoreSubmit')),
+          '#ajax' => array(
+            'callback' => array(get_class($this), 'addMoreAjax'),
+            'wrapper' => $wrapper_id,
+            'effect' => 'fade',
+          ),
+        );
+      }
+    }
+
+    return $elements;
+  }
+
+  /**
+   * Submission handler for the "Add another item" button.
+   */
+  public static function addMoreSubmit(array $form, array &$form_state) {
+    $button = $form_state['triggering_element'];
+
+    // Go one level up in the form, to the widgets container.
+    $element = NestedArray::getValue($form, array_slice($button['#array_parents'], 0, -1));
+    $field_name = $element['#field_name'];
+    $parents = $element['#field_parents'];
+
+    // Increment the items count.
+    $field_state = field_form_get_state($parents, $field_name, $form_state);
+    $field_state['items_count']++;
+    field_form_set_state($parents, $field_name, $form_state, $field_state);
+
+    $form_state['rebuild'] = TRUE;
+  }
+
+  /**
+   * Ajax callback for the "Add another item" button.
+   *
+   * This returns the new page content to replace the page content made obsolete
+   * by the form submission.
+   */
+  public static function addMoreAjax(array $form, array $form_state) {
+    $button = $form_state['triggering_element'];
+
+    // Go one level up in the form, to the widgets container.
+    $element = NestedArray::getValue($form, array_slice($button['#array_parents'], 0, -1));
+
+    // Ensure the widget allows adding additional items.
+    if ($element['#cardinality'] != FieldDefinitionInterface::CARDINALITY_UNLIMITED) {
+      return;
+    }
+
+    // Add a DIV around the delta receiving the Ajax effect.
+    $delta = $element['#max_delta'];
+    $element[$delta]['#prefix'] = '<div class="ajax-new-content">' . (isset($element[$delta]['#prefix']) ? $element[$delta]['#prefix'] : '');
+    $element[$delta]['#suffix'] = (isset($element[$delta]['#suffix']) ? $element[$delta]['#suffix'] : '') . '</div>';
+
+    return $element;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function massageMultipleFormValues(&$values) {
+    // Remove the 'value' of the 'add more' button.
+    unset($values['add_more']);
+
+    // The original delta, before drag-and-drop reordering, is needed to
+    // route errors to the corect form element.
+    foreach ($values as $delta => &$value) {
+      $value['_original_delta'] = $delta;
+    }
+
+    usort($values, function ($a, $b) {
+      return SortArray::sortByKeyInt($a, $b, '_weight');
+    });
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function deltaViolationElement(array $element, $original_delta) {
+    return $element[$original_delta];
+  }
+
+}
diff --git a/core/modules/comment/lib/Drupal/comment/Plugin/Field/FieldWidget/CommentWidget.php b/core/modules/comment/lib/Drupal/comment/Plugin/Field/FieldWidget/CommentWidget.php
index b4a8565..da9f42d 100644
--- a/core/modules/comment/lib/Drupal/comment/Plugin/Field/FieldWidget/CommentWidget.php
+++ b/core/modules/comment/lib/Drupal/comment/Plugin/Field/FieldWidget/CommentWidget.php
@@ -9,7 +9,7 @@
 
 use Drupal\comment\Plugin\Field\FieldType\CommentItemInterface;
 use Drupal\Core\Field\FieldItemListInterface;
-use Drupal\Core\Field\WidgetBase;
+use Drupal\Core\Field\WidgetBaseSingle;
 
 /**
  * Provides a default comment widget.
@@ -22,7 +22,7 @@
  *   }
  * )
  */
-class CommentWidget extends WidgetBase {
+class CommentWidget extends WidgetBaseSingle {
 
   /**
    * {@inheritdoc}
diff --git a/core/modules/datetime/lib/Drupal/datetime/Plugin/Field/FieldWidget/DateTimeDatelistWidget.php b/core/modules/datetime/lib/Drupal/datetime/Plugin/Field/FieldWidget/DateTimeDatelistWidget.php
index cbae23c..4a4dcb5 100644
--- a/core/modules/datetime/lib/Drupal/datetime/Plugin/Field/FieldWidget/DateTimeDatelistWidget.php
+++ b/core/modules/datetime/lib/Drupal/datetime/Plugin/Field/FieldWidget/DateTimeDatelistWidget.php
@@ -7,7 +7,7 @@
 namespace Drupal\datetime\Plugin\Field\FieldWidget;
 
 use Drupal\Core\Field\FieldItemListInterface;
-use Drupal\Core\Field\WidgetBase;
+use Drupal\Core\Field\WidgetBaseSingle;
 use Drupal\datetime\Plugin\Field\FieldType\DateTimeItem;
 
 /**
@@ -26,7 +26,7 @@
  *   }
  * )
  */
-class DateTimeDatelistWidget extends WidgetBase {
+class DateTimeDatelistWidget extends WidgetBaseSingle {
 
   /**
    * {@inheritdoc}
diff --git a/core/modules/datetime/lib/Drupal/datetime/Plugin/Field/FieldWidget/DateTimeDefaultWidget.php b/core/modules/datetime/lib/Drupal/datetime/Plugin/Field/FieldWidget/DateTimeDefaultWidget.php
index 9389a71..8d2f2e4 100644
--- a/core/modules/datetime/lib/Drupal/datetime/Plugin/Field/FieldWidget/DateTimeDefaultWidget.php
+++ b/core/modules/datetime/lib/Drupal/datetime/Plugin/Field/FieldWidget/DateTimeDefaultWidget.php
@@ -7,8 +7,8 @@
 namespace Drupal\datetime\Plugin\Field\FieldWidget;
 
 use Drupal\Core\Field\FieldItemListInterface;
-use Drupal\Core\Field\WidgetBase;
 use Drupal\Core\Field\FieldDefinitionInterface;
+use Drupal\Core\Field\WidgetBaseSingle;
 use Drupal\datetime\Plugin\Field\FieldType\DateTimeItem;
 
 /**
@@ -22,7 +22,7 @@
  *   }
  * )
  */
-class DateTimeDefaultWidget extends WidgetBase {
+class DateTimeDefaultWidget extends WidgetBaseSingle {
 
   /**
    * The date format storage.
diff --git a/core/modules/entity_reference/lib/Drupal/entity_reference/Plugin/Field/FieldWidget/AutocompleteTagsWidget.php b/core/modules/entity_reference/lib/Drupal/entity_reference/Plugin/Field/FieldWidget/AutocompleteTagsWidget.php
index b09f7e2..a58f4de 100644
--- a/core/modules/entity_reference/lib/Drupal/entity_reference/Plugin/Field/FieldWidget/AutocompleteTagsWidget.php
+++ b/core/modules/entity_reference/lib/Drupal/entity_reference/Plugin/Field/FieldWidget/AutocompleteTagsWidget.php
@@ -8,6 +8,11 @@
 namespace Drupal\entity_reference\Plugin\Field\FieldWidget;
 
 use Drupal\Component\Utility\Tags;
+use Drupal\Core\Field\FieldItemListInterface;
+use Drupal\Core\Field\WidgetBaseMultiple;
+use Drupal\user\EntityOwnerInterface;
+use Symfony\Component\Validator\ConstraintViolationInterface;
+
 
 /**
  * Plugin implementation of the 'entity_reference autocomplete-tags' widget.
@@ -25,10 +30,9 @@
  *     "autocomplete_type" = "tags",
  *     "placeholder" = ""
  *   },
- *   multiple_values = TRUE
  * )
  */
-class AutocompleteTagsWidget extends AutocompleteWidgetBase {
+class AutocompleteTagsWidget extends WidgetBaseMultiple {
 
   /**
    * {@inheritdoc}
@@ -78,4 +82,203 @@ public function elementValidate($element, &$form_state, $form) {
     array_pop($element['#parents']);
     form_set_value($element, $value, $form_state);
   }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function settingsForm(array $form, array &$form_state) {
+    $element['match_operator'] = array(
+      '#type' => 'radios',
+      '#title' => t('Autocomplete matching'),
+      '#default_value' => $this->getSetting('match_operator'),
+      '#options' => array(
+        'STARTS_WITH' => t('Starts with'),
+        'CONTAINS' => t('Contains'),
+      ),
+      '#description' => t('Select the method used to collect autocomplete suggestions. Note that <em>Contains</em> can cause performance issues on sites with thousands of entities.'),
+    );
+    $element['size'] = array(
+      '#type' => 'number',
+      '#title' => t('Size of textfield'),
+      '#default_value' => $this->getSetting('size'),
+      '#min' => 1,
+      '#required' => TRUE,
+    );
+    $element['placeholder'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Placeholder'),
+      '#default_value' => $this->getSetting('placeholder'),
+      '#description' => t('Text that will be shown inside the field until a value is entered. This hint is usually a sample value or a brief description of the expected format.'),
+    );
+    return $element;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function settingsSummary() {
+    $summary = array();
+
+    $summary[] = t('Autocomplete matching: @match_operator', array('@match_operator' => $this->getSetting('match_operator')));
+    $summary[] = t('Textfield size: !size', array('!size' => $this->getSetting('size')));
+    $placeholder = $this->getSetting('placeholder');
+    if (!empty($placeholder)) {
+      $summary[] = t('Placeholder: @placeholder', array('@placeholder' => $placeholder));
+    }
+    else {
+      $summary[] = t('No placeholder');
+    }
+
+    return $summary;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, array &$form_state) {
+    $entity = $items->getEntity();
+
+    // Prepare the autocomplete route parameters.
+    $autocomplete_route_parameters = array(
+      'type' => $this->getSetting('autocomplete_type'),
+      'field_name' => $this->fieldDefinition->getName(),
+      'entity_type' => $entity->getEntityTypeId(),
+      'bundle_name' => $entity->bundle(),
+    );
+
+    if ($entity_id = $entity->id()) {
+      $autocomplete_route_parameters['entity_id'] = $entity_id;
+    }
+
+    $element += array(
+      '#type' => 'textfield',
+      '#maxlength' => 1024,
+      '#default_value' => implode(', ', $this->getLabels($items, $delta)),
+      '#autocomplete_route_name' => 'entity_reference.autocomplete',
+      '#autocomplete_route_parameters' => $autocomplete_route_parameters,
+      '#size' => $this->getSetting('size'),
+      '#placeholder' => $this->getSetting('placeholder'),
+      '#element_validate' => array(array($this, 'elementValidate')),
+      '#autocreate_uid' => ($entity instanceof EntityOwnerInterface) ? $entity->getOwnerId() : \Drupal::currentUser()->id(),
+    );
+
+    return array('target_id' => $element);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function errorElement(array $element, ConstraintViolationInterface $error, array $form, array &$form_state) {
+    return $element['target_id'];
+  }
+
+  /**
+   * Gets the entity labels.
+   */
+  protected function getLabels(FieldItemListInterface $items, $delta) {
+    if ($items->isEmpty()) {
+      return array();
+    }
+
+    $entity_labels = array();
+
+    // Load those entities and loop through them to extract their labels.
+    $entities = entity_load_multiple($this->getFieldSetting('target_type'), $this->getEntityIds($items, $delta));
+
+    foreach ($entities as $entity_id => $entity_item) {
+      $label = $entity_item->label();
+      $key = "$label ($entity_id)";
+      // Labels containing commas or quotes must be wrapped in quotes.
+      $key = Tags::encode($key);
+      $entity_labels[] = $key;
+    }
+    return $entity_labels;
+  }
+
+  /**
+   * Builds an array of entity IDs for which to get the entity labels.
+   *
+   * @param \Drupal\Core\Field\FieldItemListInterface $items
+   *   Array of default values for this field.
+   * @param int $delta
+   *   The order of a field item in the array of subelements (0, 1, 2, etc).
+   *
+   * @return array
+   *   An array of entity IDs.
+   */
+  protected function getEntityIds(FieldItemListInterface $items, $delta) {
+    $entity_ids = array();
+
+    foreach ($items as $item) {
+      $entity_ids[] = $item->target_id;
+    }
+
+    return $entity_ids;
+  }
+
+  /**
+   * Creates a new entity from a label entered in the autocomplete input.
+   *
+   * @param string $label
+   *   The entity label.
+   * @param int $uid
+   *   The entity uid.
+   *
+   * @return \Drupal\Core\Entity\EntityInterface
+   */
+  protected function createNewEntity($label, $uid) {
+    $entity_manager = \Drupal::entityManager();
+    $target_type = $this->getFieldSetting('target_type');
+    $target_bundles = $this->getSelectionHandlerSetting('target_bundles');
+
+    // Get the bundle.
+    if (!empty($target_bundles)) {
+      $bundle = reset($target_bundles);
+    }
+    else {
+      $bundles = entity_get_bundles($target_type);
+      $bundle = reset($bundles);
+    }
+
+    $entity_type = $entity_manager->getDefinition($target_type);
+    $bundle_key = $entity_type->getKey('bundle');
+    $label_key = $entity_type->getKey('label');
+
+    $entity = $entity_manager->getStorageController($target_type)->create(array(
+      $label_key => $label,
+      $bundle_key => $bundle,
+    ));
+
+    if ($entity instanceof EntityOwnerInterface) {
+      $entity->setOwnerId($uid);
+    }
+
+    return $entity;
+  }
+
+  /**
+   * Returns the value of a setting for the entity reference selection handler.
+   *
+   * @param string $setting_name
+   *   The setting name.
+   *
+   * @return mixed
+   *   The setting value.
+   */
+  protected function getSelectionHandlerSetting($setting_name) {
+    $settings = $this->getFieldSetting('handler_settings');
+    return isset($settings[$setting_name]) ? $settings[$setting_name] : NULL;
+  }
+
+  /**
+   * Checks whether a content entity is referenced.
+   *
+   * @return bool
+   */
+  protected function isContentReferenced() {
+    $target_type = $this->getFieldSetting('target_type');
+    $target_type_info = \Drupal::entityManager()->getDefinition($target_type);
+    return $target_type_info->isSubclassOf('\Drupal\Core\Entity\ContentEntityInterface');
+  }
+
 }
diff --git a/core/modules/entity_reference/lib/Drupal/entity_reference/Plugin/Field/FieldWidget/AutocompleteWidget.php b/core/modules/entity_reference/lib/Drupal/entity_reference/Plugin/Field/FieldWidget/AutocompleteWidget.php
index 0898d68..f50680b 100644
--- a/core/modules/entity_reference/lib/Drupal/entity_reference/Plugin/Field/FieldWidget/AutocompleteWidget.php
+++ b/core/modules/entity_reference/lib/Drupal/entity_reference/Plugin/Field/FieldWidget/AutocompleteWidget.php
@@ -8,6 +8,11 @@
 namespace Drupal\entity_reference\Plugin\Field\FieldWidget;
 
 use Drupal\Core\Field\FieldItemListInterface;
+use Drupal\Component\Utility\Tags;
+use Drupal\Core\Field\WidgetBaseSingle;
+use Drupal\user\EntityOwnerInterface;
+use Symfony\Component\Validator\ConstraintViolationInterface;
+
 
 /**
  * Plugin implementation of the 'entity_reference autocomplete' widget.
@@ -32,7 +37,7 @@
  *   }
  * )
  */
-class AutocompleteWidget extends AutocompleteWidgetBase {
+class AutocompleteWidget extends WidgetBaseSingle {
 
   /**
    * {@inheritdoc}
@@ -87,4 +92,182 @@ public function elementValidate($element, &$form_state, $form) {
     }
     form_set_value($element, $value, $form_state);
   }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function settingsForm(array $form, array &$form_state) {
+    $element['match_operator'] = array(
+      '#type' => 'radios',
+      '#title' => t('Autocomplete matching'),
+      '#default_value' => $this->getSetting('match_operator'),
+      '#options' => array(
+        'STARTS_WITH' => t('Starts with'),
+        'CONTAINS' => t('Contains'),
+      ),
+      '#description' => t('Select the method used to collect autocomplete suggestions. Note that <em>Contains</em> can cause performance issues on sites with thousands of entities.'),
+    );
+    $element['size'] = array(
+      '#type' => 'number',
+      '#title' => t('Size of textfield'),
+      '#default_value' => $this->getSetting('size'),
+      '#min' => 1,
+      '#required' => TRUE,
+    );
+    $element['placeholder'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Placeholder'),
+      '#default_value' => $this->getSetting('placeholder'),
+      '#description' => t('Text that will be shown inside the field until a value is entered. This hint is usually a sample value or a brief description of the expected format.'),
+    );
+    return $element;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function settingsSummary() {
+    $summary = array();
+
+    $summary[] = t('Autocomplete matching: @match_operator', array('@match_operator' => $this->getSetting('match_operator')));
+    $summary[] = t('Textfield size: !size', array('!size' => $this->getSetting('size')));
+    $placeholder = $this->getSetting('placeholder');
+    if (!empty($placeholder)) {
+      $summary[] = t('Placeholder: @placeholder', array('@placeholder' => $placeholder));
+    }
+    else {
+      $summary[] = t('No placeholder');
+    }
+
+    return $summary;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, array &$form_state) {
+    $entity = $items->getEntity();
+
+    // Prepare the autocomplete route parameters.
+    $autocomplete_route_parameters = array(
+      'type' => $this->getSetting('autocomplete_type'),
+      'field_name' => $this->fieldDefinition->getName(),
+      'entity_type' => $entity->getEntityTypeId(),
+      'bundle_name' => $entity->bundle(),
+    );
+
+    if ($entity_id = $entity->id()) {
+      $autocomplete_route_parameters['entity_id'] = $entity_id;
+    }
+
+    $element += array(
+      '#type' => 'textfield',
+      '#maxlength' => 1024,
+      '#default_value' => implode(', ', $this->getLabels($items, $delta)),
+      '#autocomplete_route_name' => 'entity_reference.autocomplete',
+      '#autocomplete_route_parameters' => $autocomplete_route_parameters,
+      '#size' => $this->getSetting('size'),
+      '#placeholder' => $this->getSetting('placeholder'),
+      '#element_validate' => array(array($this, 'elementValidate')),
+      '#autocreate_uid' => ($entity instanceof EntityOwnerInterface) ? $entity->getOwnerId() : \Drupal::currentUser()->id(),
+    );
+
+    return array('target_id' => $element);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function errorElement(array $element, ConstraintViolationInterface $error, array $form, array &$form_state) {
+    return $element['target_id'];
+  }
+
+  /**
+   * Gets the entity labels.
+   */
+  protected function getLabels(FieldItemListInterface $items, $delta) {
+    if ($items->isEmpty()) {
+      return array();
+    }
+
+    $entity_labels = array();
+
+    // Load those entities and loop through them to extract their labels.
+    $entities = entity_load_multiple($this->getFieldSetting('target_type'), $this->getEntityIds($items, $delta));
+
+    foreach ($entities as $entity_id => $entity_item) {
+      $label = $entity_item->label();
+      $key = "$label ($entity_id)";
+      // Labels containing commas or quotes must be wrapped in quotes.
+      $key = Tags::encode($key);
+      $entity_labels[] = $key;
+    }
+    return $entity_labels;
+  }
+
+  /**
+   * Creates a new entity from a label entered in the autocomplete input.
+   *
+   * @param string $label
+   *   The entity label.
+   * @param int $uid
+   *   The entity uid.
+   *
+   * @return \Drupal\Core\Entity\EntityInterface
+   */
+  protected function createNewEntity($label, $uid) {
+    $entity_manager = \Drupal::entityManager();
+    $target_type = $this->getFieldSetting('target_type');
+    $target_bundles = $this->getSelectionHandlerSetting('target_bundles');
+
+    // Get the bundle.
+    if (!empty($target_bundles)) {
+      $bundle = reset($target_bundles);
+    }
+    else {
+      $bundles = entity_get_bundles($target_type);
+      $bundle = reset($bundles);
+    }
+
+    $entity_type = $entity_manager->getDefinition($target_type);
+    $bundle_key = $entity_type->getKey('bundle');
+    $label_key = $entity_type->getKey('label');
+
+    $entity = $entity_manager->getStorageController($target_type)->create(array(
+      $label_key => $label,
+      $bundle_key => $bundle,
+    ));
+
+    if ($entity instanceof EntityOwnerInterface) {
+      $entity->setOwnerId($uid);
+    }
+
+    return $entity;
+  }
+
+  /**
+   * Returns the value of a setting for the entity reference selection handler.
+   *
+   * @param string $setting_name
+   *   The setting name.
+   *
+   * @return mixed
+   *   The setting value.
+   */
+  protected function getSelectionHandlerSetting($setting_name) {
+    $settings = $this->getFieldSetting('handler_settings');
+    return isset($settings[$setting_name]) ? $settings[$setting_name] : NULL;
+  }
+
+  /**
+   * Checks whether a content entity is referenced.
+   *
+   * @return bool
+   */
+  protected function isContentReferenced() {
+    $target_type = $this->getFieldSetting('target_type');
+    $target_type_info = \Drupal::entityManager()->getDefinition($target_type);
+    return $target_type_info->isSubclassOf('\Drupal\Core\Entity\ContentEntityInterface');
+  }
+
 }
diff --git a/core/modules/entity_reference/lib/Drupal/entity_reference/Plugin/Field/FieldWidget/AutocompleteWidgetBase.php b/core/modules/entity_reference/lib/Drupal/entity_reference/Plugin/Field/FieldWidget/AutocompleteWidgetBase.php
deleted file mode 100644
index 66849a7..0000000
--- a/core/modules/entity_reference/lib/Drupal/entity_reference/Plugin/Field/FieldWidget/AutocompleteWidgetBase.php
+++ /dev/null
@@ -1,224 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\entity_reference\Plugin\Field\FieldWidget\AutocompleteWidgetBase.
- */
-
-namespace Drupal\entity_reference\Plugin\Field\FieldWidget;
-
-use Drupal\Component\Utility\Tags;
-use Drupal\Core\Field\FieldItemListInterface;
-use Drupal\Core\Field\WidgetBase;
-use Drupal\user\EntityOwnerInterface;
-use Symfony\Component\Validator\ConstraintViolationInterface;
-
-/**
- * Parent plugin for entity reference autocomplete widgets.
- */
-abstract class AutocompleteWidgetBase extends WidgetBase {
-
-  /**
-   * {@inheritdoc}
-   */
-  public function settingsForm(array $form, array &$form_state) {
-    $element['match_operator'] = array(
-      '#type' => 'radios',
-      '#title' => t('Autocomplete matching'),
-      '#default_value' => $this->getSetting('match_operator'),
-      '#options' => array(
-        'STARTS_WITH' => t('Starts with'),
-        'CONTAINS' => t('Contains'),
-      ),
-      '#description' => t('Select the method used to collect autocomplete suggestions. Note that <em>Contains</em> can cause performance issues on sites with thousands of entities.'),
-    );
-    $element['size'] = array(
-      '#type' => 'number',
-      '#title' => t('Size of textfield'),
-      '#default_value' => $this->getSetting('size'),
-      '#min' => 1,
-      '#required' => TRUE,
-    );
-    $element['placeholder'] = array(
-      '#type' => 'textfield',
-      '#title' => t('Placeholder'),
-      '#default_value' => $this->getSetting('placeholder'),
-      '#description' => t('Text that will be shown inside the field until a value is entered. This hint is usually a sample value or a brief description of the expected format.'),
-    );
-    return $element;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function settingsSummary() {
-    $summary = array();
-
-    $summary[] = t('Autocomplete matching: @match_operator', array('@match_operator' => $this->getSetting('match_operator')));
-    $summary[] = t('Textfield size: !size', array('!size' => $this->getSetting('size')));
-    $placeholder = $this->getSetting('placeholder');
-    if (!empty($placeholder)) {
-      $summary[] = t('Placeholder: @placeholder', array('@placeholder' => $placeholder));
-    }
-    else {
-      $summary[] = t('No placeholder');
-    }
-
-    return $summary;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, array &$form_state) {
-    $entity = $items->getEntity();
-
-    // Prepare the autocomplete route parameters.
-    $autocomplete_route_parameters = array(
-      'type' => $this->getSetting('autocomplete_type'),
-      'field_name' => $this->fieldDefinition->getName(),
-      'entity_type' => $entity->getEntityTypeId(),
-      'bundle_name' => $entity->bundle(),
-    );
-
-    if ($entity_id = $entity->id()) {
-      $autocomplete_route_parameters['entity_id'] = $entity_id;
-    }
-
-    $element += array(
-      '#type' => 'textfield',
-      '#maxlength' => 1024,
-      '#default_value' => implode(', ', $this->getLabels($items, $delta)),
-      '#autocomplete_route_name' => 'entity_reference.autocomplete',
-      '#autocomplete_route_parameters' => $autocomplete_route_parameters,
-      '#size' => $this->getSetting('size'),
-      '#placeholder' => $this->getSetting('placeholder'),
-      '#element_validate' => array(array($this, 'elementValidate')),
-      '#autocreate_uid' => ($entity instanceof EntityOwnerInterface) ? $entity->getOwnerId() : \Drupal::currentUser()->id(),
-    );
-
-    return array('target_id' => $element);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function errorElement(array $element, ConstraintViolationInterface $error, array $form, array &$form_state) {
-    return $element['target_id'];
-  }
-
-  /**
-   * Validates an element.
-   */
-  public function elementValidate($element, &$form_state, $form) { }
-
-  /**
-   * Gets the entity labels.
-   */
-  protected function getLabels(FieldItemListInterface $items, $delta) {
-    if ($items->isEmpty()) {
-      return array();
-    }
-
-    $entity_labels = array();
-
-    // Load those entities and loop through them to extract their labels.
-    $entities = entity_load_multiple($this->getFieldSetting('target_type'), $this->getEntityIds($items, $delta));
-
-    foreach ($entities as $entity_id => $entity_item) {
-      $label = $entity_item->label();
-      $key = "$label ($entity_id)";
-      // Labels containing commas or quotes must be wrapped in quotes.
-      $key = Tags::encode($key);
-      $entity_labels[] = $key;
-    }
-    return $entity_labels;
-  }
-
-  /**
-   * Builds an array of entity IDs for which to get the entity labels.
-   *
-   * @param \Drupal\Core\Field\FieldItemListInterface $items
-   *   Array of default values for this field.
-   * @param int $delta
-   *   The order of a field item in the array of subelements (0, 1, 2, etc).
-   *
-   * @return array
-   *   An array of entity IDs.
-   */
-  protected function getEntityIds(FieldItemListInterface $items, $delta) {
-    $entity_ids = array();
-
-    foreach ($items as $item) {
-      $entity_ids[] = $item->target_id;
-    }
-
-    return $entity_ids;
-  }
-
-  /**
-   * Creates a new entity from a label entered in the autocomplete input.
-   *
-   * @param string $label
-   *   The entity label.
-   * @param int $uid
-   *   The entity uid.
-   *
-   * @return \Drupal\Core\Entity\EntityInterface
-   */
-  protected function createNewEntity($label, $uid) {
-    $entity_manager = \Drupal::entityManager();
-    $target_type = $this->getFieldSetting('target_type');
-    $target_bundles = $this->getSelectionHandlerSetting('target_bundles');
-
-    // Get the bundle.
-    if (!empty($target_bundles)) {
-      $bundle = reset($target_bundles);
-    }
-    else {
-      $bundles = entity_get_bundles($target_type);
-      $bundle = reset($bundles);
-    }
-
-    $entity_type = $entity_manager->getDefinition($target_type);
-    $bundle_key = $entity_type->getKey('bundle');
-    $label_key = $entity_type->getKey('label');
-
-    $entity = $entity_manager->getStorageController($target_type)->create(array(
-      $label_key => $label,
-      $bundle_key => $bundle,
-    ));
-
-    if ($entity instanceof EntityOwnerInterface) {
-      $entity->setOwnerId($uid);
-    }
-
-    return $entity;
-  }
-
-  /**
-   * Returns the value of a setting for the entity reference selection handler.
-   *
-   * @param string $setting_name
-   *   The setting name.
-   *
-   * @return mixed
-   *   The setting value.
-   */
-  protected function getSelectionHandlerSetting($setting_name) {
-    $settings = $this->getFieldSetting('handler_settings');
-    return isset($settings[$setting_name]) ? $settings[$setting_name] : NULL;
-  }
-
-  /**
-   * Checks whether a content entity is referenced.
-   *
-   * @return bool
-   */
-  protected function isContentReferenced() {
-    $target_type = $this->getFieldSetting('target_type');
-    $target_type_info = \Drupal::entityManager()->getDefinition($target_type);
-    return $target_type_info->isSubclassOf('\Drupal\Core\Entity\ContentEntityInterface');
-  }
-
-}
diff --git a/core/modules/field/tests/modules/field_test/lib/Drupal/field_test/Plugin/Field/FieldWidget/TestFieldWidget.php b/core/modules/field/tests/modules/field_test/lib/Drupal/field_test/Plugin/Field/FieldWidget/TestFieldWidget.php
index ae80042..a57004e 100644
--- a/core/modules/field/tests/modules/field_test/lib/Drupal/field_test/Plugin/Field/FieldWidget/TestFieldWidget.php
+++ b/core/modules/field/tests/modules/field_test/lib/Drupal/field_test/Plugin/Field/FieldWidget/TestFieldWidget.php
@@ -8,7 +8,7 @@
 namespace Drupal\field_test\Plugin\Field\FieldWidget;
 
 use Drupal\Core\Field\FieldItemListInterface;
-use Drupal\Core\Field\WidgetBase;
+use Drupal\Core\Field\WidgetBaseSingle;
 use Symfony\Component\Validator\ConstraintViolationInterface;
 
 /**
@@ -27,7 +27,7 @@
  *   weight = -10
  * )
  */
-class TestFieldWidget extends WidgetBase {
+class TestFieldWidget extends WidgetBaseSingle {
 
   /**
    * {@inheritdoc}
diff --git a/core/modules/field/tests/modules/field_test/lib/Drupal/field_test/Plugin/Field/FieldWidget/TestFieldWidgetMultiple.php b/core/modules/field/tests/modules/field_test/lib/Drupal/field_test/Plugin/Field/FieldWidget/TestFieldWidgetMultiple.php
index a16eb3f..a5e25db 100644
--- a/core/modules/field/tests/modules/field_test/lib/Drupal/field_test/Plugin/Field/FieldWidget/TestFieldWidgetMultiple.php
+++ b/core/modules/field/tests/modules/field_test/lib/Drupal/field_test/Plugin/Field/FieldWidget/TestFieldWidgetMultiple.php
@@ -8,7 +8,7 @@
 namespace Drupal\field_test\Plugin\Field\FieldWidget;
 
 use Drupal\Core\Field\FieldItemListInterface;
-use Drupal\Core\Field\WidgetBase;
+use Drupal\Core\Field\WidgetBaseMultiple;
 use Symfony\Component\Validator\ConstraintViolationInterface;
 
 /**
@@ -25,11 +25,10 @@
  *   settings = {
  *     "test_widget_setting_multiple" = "dummy test string"
  *   },
- *   multiple_values = TRUE,
  *   weight = 10
  * )
  */
-class TestFieldWidgetMultiple extends WidgetBase {
+class TestFieldWidgetMultiple extends WidgetBaseMultiple {
 
   /**
    * {@inheritdoc}
diff --git a/core/modules/file/lib/Drupal/file/Plugin/Field/FieldWidget/FileWidget.php b/core/modules/file/lib/Drupal/file/Plugin/Field/FieldWidget/FileWidget.php
index 9267eae..a24e52f 100644
--- a/core/modules/file/lib/Drupal/file/Plugin/Field/FieldWidget/FileWidget.php
+++ b/core/modules/file/lib/Drupal/file/Plugin/Field/FieldWidget/FileWidget.php
@@ -8,9 +8,9 @@
 namespace Drupal\file\Plugin\Field\FieldWidget;
 
 use Drupal\Core\Field\FieldDefinitionInterface;
-use Drupal\Core\Field\WidgetBase;
 use Drupal\Core\Field\FieldItemListInterface;
 use Drupal\Component\Utility\NestedArray;
+use Drupal\Core\Field\WidgetBaseSingle;
 use Drupal\field\Field;
 
 /**
@@ -27,8 +27,7 @@
  *   }
  * )
  */
-class FileWidget extends WidgetBase {
-
+class FileWidget extends WidgetBaseSingle {
   /**
    * {@inheritdoc}
    */
diff --git a/core/modules/link/lib/Drupal/link/Plugin/Field/FieldWidget/LinkWidget.php b/core/modules/link/lib/Drupal/link/Plugin/Field/FieldWidget/LinkWidget.php
index dc10574..7c00ac6 100644
--- a/core/modules/link/lib/Drupal/link/Plugin/Field/FieldWidget/LinkWidget.php
+++ b/core/modules/link/lib/Drupal/link/Plugin/Field/FieldWidget/LinkWidget.php
@@ -8,7 +8,7 @@
 namespace Drupal\link\Plugin\Field\FieldWidget;
 
 use Drupal\Core\Field\FieldItemListInterface;
-use Drupal\Core\Field\WidgetBase;
+use Drupal\Core\Field\WidgetBaseSingle;
 
 /**
  * Plugin implementation of the 'link' widget.
@@ -25,7 +25,7 @@
  *   }
  * )
  */
-class LinkWidget extends WidgetBase {
+class LinkWidget extends WidgetBaseSingle {
 
   /**
    * {@inheritdoc}
diff --git a/core/modules/options/lib/Drupal/options/Plugin/Field/FieldWidget/ButtonsWidget.php b/core/modules/options/lib/Drupal/options/Plugin/Field/FieldWidget/ButtonsWidget.php
index 9746b0f..ab88e38 100644
--- a/core/modules/options/lib/Drupal/options/Plugin/Field/FieldWidget/ButtonsWidget.php
+++ b/core/modules/options/lib/Drupal/options/Plugin/Field/FieldWidget/ButtonsWidget.php
@@ -22,7 +22,6 @@
  *     "list_text",
  *     "list_boolean"
  *   },
- *   multiple_values = TRUE
  * )
  */
 class ButtonsWidget extends OptionsWidgetBase {
diff --git a/core/modules/options/lib/Drupal/options/Plugin/Field/FieldWidget/OnOffWidget.php b/core/modules/options/lib/Drupal/options/Plugin/Field/FieldWidget/OnOffWidget.php
index 34b741e..d32aebb 100644
--- a/core/modules/options/lib/Drupal/options/Plugin/Field/FieldWidget/OnOffWidget.php
+++ b/core/modules/options/lib/Drupal/options/Plugin/Field/FieldWidget/OnOffWidget.php
@@ -22,7 +22,6 @@
  *   settings = {
  *     "display_label" = FALSE,
  *   },
- *   multiple_values = TRUE
  * )
  */
 class OnOffWidget extends OptionsWidgetBase {
diff --git a/core/modules/options/lib/Drupal/options/Plugin/Field/FieldWidget/OptionsWidgetBase.php b/core/modules/options/lib/Drupal/options/Plugin/Field/FieldWidget/OptionsWidgetBase.php
index c23de90..460a78b 100644
--- a/core/modules/options/lib/Drupal/options/Plugin/Field/FieldWidget/OptionsWidgetBase.php
+++ b/core/modules/options/lib/Drupal/options/Plugin/Field/FieldWidget/OptionsWidgetBase.php
@@ -10,7 +10,7 @@
 use Drupal\Core\Field\FieldDefinitionInterface;
 use Drupal\Core\Field\FieldItemListInterface;
 use Drupal\Core\Field\FieldItemInterface;
-use Drupal\Core\Field\WidgetBase;
+use Drupal\Core\Field\WidgetBaseMultiple;
 
 /**
  * Base class for the 'options_*' widgets.
@@ -22,7 +22,7 @@
  *
  * @see \Drupal\Core\TypedData\AllowedValuesInterface
  */
-abstract class OptionsWidgetBase extends WidgetBase {
+abstract class OptionsWidgetBase extends WidgetBaseMultiple {
 
   /**
    * Identifies a 'None' option.
diff --git a/core/modules/options/lib/Drupal/options/Plugin/Field/FieldWidget/SelectWidget.php b/core/modules/options/lib/Drupal/options/Plugin/Field/FieldWidget/SelectWidget.php
index 6d37440..c3975b7 100644
--- a/core/modules/options/lib/Drupal/options/Plugin/Field/FieldWidget/SelectWidget.php
+++ b/core/modules/options/lib/Drupal/options/Plugin/Field/FieldWidget/SelectWidget.php
@@ -21,7 +21,6 @@
  *     "list_float",
  *     "list_text"
  *   },
- *   multiple_values = TRUE
  * )
  */
 class SelectWidget extends OptionsWidgetBase {
diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/Plugin/Field/FieldWidget/TaxonomyAutocompleteWidget.php b/core/modules/taxonomy/lib/Drupal/taxonomy/Plugin/Field/FieldWidget/TaxonomyAutocompleteWidget.php
index 7c20732..28bd8a5 100644
--- a/core/modules/taxonomy/lib/Drupal/taxonomy/Plugin/Field/FieldWidget/TaxonomyAutocompleteWidget.php
+++ b/core/modules/taxonomy/lib/Drupal/taxonomy/Plugin/Field/FieldWidget/TaxonomyAutocompleteWidget.php
@@ -8,7 +8,7 @@
 namespace Drupal\taxonomy\Plugin\Field\FieldWidget;
 
 use Drupal\Core\Field\FieldItemListInterface;
-use Drupal\Core\Field\WidgetBase;
+use Drupal\Core\Field\WidgetBaseMultiple;
 
 /**
  * Plugin implementation of the 'taxonomy_autocomplete' widget.
@@ -24,10 +24,9 @@
  *     "autocomplete_route_name" = "taxonomy.autocomplete",
  *     "placeholder" = ""
  *   },
- *   multiple_values = TRUE
  * )
  */
-class TaxonomyAutocompleteWidget extends WidgetBase {
+class TaxonomyAutocompleteWidget extends WidgetBaseMultiple {
 
   /**
    * {@inheritdoc}
diff --git a/core/modules/telephone/lib/Drupal/telephone/Plugin/Field/FieldWidget/TelephoneDefaultWidget.php b/core/modules/telephone/lib/Drupal/telephone/Plugin/Field/FieldWidget/TelephoneDefaultWidget.php
index 78c768e..5476eb1 100644
--- a/core/modules/telephone/lib/Drupal/telephone/Plugin/Field/FieldWidget/TelephoneDefaultWidget.php
+++ b/core/modules/telephone/lib/Drupal/telephone/Plugin/Field/FieldWidget/TelephoneDefaultWidget.php
@@ -8,7 +8,7 @@
 namespace Drupal\telephone\Plugin\Field\FieldWidget;
 
 use Drupal\Core\Field\FieldItemListInterface;
-use Drupal\Core\Field\WidgetBase;
+use Drupal\Core\Field\WidgetBaseSingle;
 
 /**
  * Plugin implementation of the 'telephone_default' widget.
@@ -24,7 +24,7 @@
  *   }
  * )
  */
-class TelephoneDefaultWidget extends WidgetBase {
+class TelephoneDefaultWidget extends WidgetBaseSingle {
 
 
   /**
diff --git a/core/modules/text/lib/Drupal/text/Plugin/Field/FieldWidget/TextareaWidget.php b/core/modules/text/lib/Drupal/text/Plugin/Field/FieldWidget/TextareaWidget.php
index 9752a1f..dbf009d 100644
--- a/core/modules/text/lib/Drupal/text/Plugin/Field/FieldWidget/TextareaWidget.php
+++ b/core/modules/text/lib/Drupal/text/Plugin/Field/FieldWidget/TextareaWidget.php
@@ -8,7 +8,7 @@
 namespace Drupal\text\Plugin\Field\FieldWidget;
 
 use Drupal\Core\Field\FieldItemListInterface;
-use Drupal\Core\Field\WidgetBase;
+use Drupal\Core\Field\WidgetBaseSingle;
 use Symfony\Component\Validator\ConstraintViolationInterface;
 
 /**
@@ -26,7 +26,7 @@
  *   }
  * )
  */
-class TextareaWidget extends WidgetBase {
+class TextareaWidget extends WidgetBaseSingle {
 
   /**
    * {@inheritdoc}
