diff --git a/core/lib/Drupal/Core/Field/WidgetBase.php b/core/lib/Drupal/Core/Field/WidgetBase.php
index ffa82d1ed302bf2cb266b6da84b91bd02f79d8fa..539ac9f05c8e2c51a3749cc68efa03d78387977c 100644
--- a/core/lib/Drupal/Core/Field/WidgetBase.php
+++ b/core/lib/Drupal/Core/Field/WidgetBase.php
@@ -8,6 +8,7 @@
 namespace Drupal\Core\Field;
 
 use Drupal\Component\Utility\NestedArray;
+use Drupal\Component\Utility\SortArray;
 use Symfony\Component\Validator\ConstraintViolationInterface;
 
 /**
@@ -70,8 +71,7 @@ public function form(FieldItemListInterface $items, array &$form, array &$form_s
     // 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.
-    $definition = $this->getPluginDefinition();
-    if (isset($get_delta) || $definition['multiple_values']) {
+    if ($this->handlesMultipleValues() || isset($get_delta)) {
       $delta = isset($get_delta) ? $get_delta : 0;
       $element = array(
         '#title' => check_plain($this->fieldDefinition->getLabel()),
@@ -278,44 +278,38 @@ public function extractFormValues(FieldItemListInterface $items, array $form, ar
     $values = NestedArray::getValue($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();
-      // Check that $values[0] is an array, because if it's a string, then in
-      // PHP 5.3, ['_weight'] returns the first character.
-      if (isset($values[0]) && is_array($values[0]) && isset($values[0]['_weight'])) {
-        foreach ($values as $delta => $value) {
-          $weights[$delta] = $value['_weight'];
+      // 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;
         }
-      }
-      $items->setValue($this->massageFormValues($values, $form, $form_state));
 
-      foreach ($items as $delta => $item) {
-        // Put back the weight.
-        if (isset($weights[$delta])) {
-          $item->_weight = $weights[$delta];
-        }
-        // The tasks below are going to reshuffle deltas. Keep track of the
-        // original deltas for correct reporting of errors in flagErrors().
-        $item->_original_delta = $delta;
+        usort($values, function ($a, $b) {
+          return SortArray::sortByKeyInt($a, $b, '_weight');
+        });
       }
 
-      // Account for drag-n-drop reordering.
-      $this->sortItems($items);
+      // Let the widget massage the submitted values.
+      $values = $this->massageFormValues($values, $form, $form_state);
 
-      // Remove empty values.
+      // Assign the values and remove the empty ones.
+      $items->setValue($values);
       $items->filterEmptyItems();
 
       // Put delta mapping in $form_state, so that flagErrors() can use it.
       $field_state = field_form_get_state($form['#parents'], $field_name, $form_state);
       foreach ($items as $delta => $item) {
-        $field_state['original_deltas'][$delta] = $item->_original_delta;
-        unset($item->_original_delta);
+        $field_state['original_deltas'][$delta] = isset($item->_original_delta) ? $item->_original_delta : $delta;
+        unset($item->_original_delta, $item->_weight);
       }
       field_form_set_state($form['#parents'], $field_name, $form_state, $field_state);
+
+      return;
     }
   }
 
@@ -348,8 +342,7 @@ public function flagErrors(FieldItemListInterface $items, array $form, array &$f
 
       // Only set errors if the element is accessible.
       if (!isset($element['#access']) || $element['#access']) {
-        $definition = $this->getPluginDefinition();
-        $is_multiple = $definition['multiple_values'];
+        $handles_multiple = $this->handlesMultipleValues();
 
         $violations_by_delta = array();
         foreach ($field_state['constraint_violations'] as $violation) {
@@ -368,7 +361,7 @@ 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 ($is_multiple || $delta === NULL) {
+          if ($handles_multiple || $delta === NULL) {
             $delta_element = $element;
           }
           // Otherwise, pass errors by delta to the corresponding sub-element.
@@ -419,28 +412,6 @@ public function massageFormValues(array $values, array $form, array &$form_state
     return $values;
   }
 
-  /**
-   * Sorts submitted field values according to drag-n-drop reordering.
-   *
-   * @param \Drupal\Core\Field\FieldItemListInterface $items
-   *   The field values.
-   */
-  protected function sortItems(FieldItemListInterface $items) {
-    if ($this->fieldDefinition->isMultiple() && isset($items[0]->_weight)) {
-      $itemValues = $items->getValue(TRUE);
-      usort($itemValues, function ($a, $b) {
-        $a_weight = (is_array($a) ? $a['_weight'] : 0);
-        $b_weight = (is_array($b) ? $b['_weight'] : 0);
-        return $a_weight - $b_weight;
-      });
-      $items->setValue($itemValues);
-      // Remove the '_weight' entries.
-      foreach ($items as $item) {
-        unset($item->_weight);
-      }
-    }
-  }
-
   /**
    * Returns the array of field settings.
    *
@@ -464,4 +435,16 @@ 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'];
+  }
+
 }