diff --git a/core/modules/image/image.post_update.php b/core/modules/image/image.post_update.php
index cde93fc2e9..fb3bfd3189 100644
--- a/core/modules/image/image.post_update.php
+++ b/core/modules/image/image.post_update.php
@@ -37,3 +37,10 @@ function image_post_update_scale_and_crop_effect_add_anchor(&$sandbox = NULL) {
     return FALSE;
   });
 }
+
+/**
+ * Fix problem with image dimensions when using multiple upload.
+ */
+function image_post_update_multiple_upload_fix_with_dimensions() {
+  \Drupal::messenger()->addMessage(t('Fixed problem with incorrect processing of image dimensions when using multiple upload. To eliminate this problem for already existing records see <a href="https://www.drupal.org/project/drupal/issues/2967586">https://www.drupal.org/project/drupal/issues/2967586</a>'), 'status');
+}
diff --git a/core/modules/image/src/Plugin/Field/FieldWidget/ImageWidget.php b/core/modules/image/src/Plugin/Field/FieldWidget/ImageWidget.php
index 304e0979c1..94a8d7ed1e 100644
--- a/core/modules/image/src/Plugin/Field/FieldWidget/ImageWidget.php
+++ b/core/modules/image/src/Plugin/Field/FieldWidget/ImageWidget.php
@@ -186,6 +186,33 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen
     return $element;
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function massageFormValues(array $values, array $form, FormStateInterface $form_state) {
+    // Since file upload widget now supports uploads of more than one file at a
+    // time it always returns an array of fids. We have to translate this to a
+    // single fid, as field expects single value. In this process, we have to
+    // unset any image dimension for files after the first, that would
+    // otherwise be copied from the ones of the first file.
+    $new_values = [];
+    foreach ($values as &$value) {
+      $first = true;
+      foreach ($value['fids'] as $fid) {
+        $new_value = $value;
+        $new_value['target_id'] = $fid;
+        unset($new_value['fids']);
+        if (!$first) {
+          unset($new_value['width'], $new_value['height']);
+        }
+        $new_values[] = $new_value;
+        $first = false;
+      }
+    }
+
+    return $new_values;
+  }
+
   /**
    * Form API callback: Processes a image_image field element.
    *
@@ -286,6 +313,70 @@ public static function process($element, FormStateInterface $form_state, $form)
     return parent::process($element, $form_state, $form);
   }
 
+  /**
+   * Form submission handler for upload/remove button of formElement().
+   *
+   * This runs in addition to and after file_managed_file_submit().
+   *
+   * @see file_managed_file_submit()
+   */
+  public static function submit($form, FormStateInterface $form_state) {
+    // During the form rebuild, formElement() will create field item widget
+    // elements using re-indexed deltas, so clear out FormState::$input to
+    // avoid a mismatch between old and new deltas. The rebuilt elements will
+    // have #default_value set appropriately for the current state of the field,
+    // so nothing is lost in doing this.
+    $button = $form_state->getTriggeringElement();
+    $parents = array_slice($button['#parents'], 0, -2);
+    NestedArray::setValue($form_state->getUserInput(), $parents, NULL);
+
+    // 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'];
+
+    $submitted_values = NestedArray::getValue($form_state->getValues(), array_slice($button['#parents'], 0, -2));
+    foreach ($submitted_values as $delta => $submitted_value) {
+      if (empty($submitted_value['fids'])) {
+        unset($submitted_values[$delta]);
+      }
+    }
+
+    // If there are more files uploaded via the same widget, we have to
+    // separate them, as we display each file in its own widget. In this
+    // process, we have to unset any image dimension for files after the first,
+    // that would otherwise be copied from the ones of the first file.
+    $new_values = [];
+    foreach ($submitted_values as $delta => $submitted_value) {
+      if (is_array($submitted_value['fids'])) {
+        $first = TRUE;
+        foreach ($submitted_value['fids'] as $fid) {
+          $new_value = $submitted_value;
+          $new_value['fids'] = [$fid];
+          if (!$first) {
+            unset($new_value['width'], $new_value['height']);
+          }
+          $new_values[] = $new_value;
+          $first = FALSE;
+        }
+      }
+      else {
+        $new_value = $submitted_value;
+      }
+    }
+
+    // Re-index deltas after removing empty items.
+    $submitted_values = array_values($new_values);
+
+    // Update form_state values.
+    NestedArray::setValue($form_state->getValues(), array_slice($button['#parents'], 0, -2), $submitted_values);
+
+    // Update items.
+    $field_state = static::getWidgetState($parents, $field_name, $form_state);
+    $field_state['items'] = $submitted_values;
+    static::setWidgetState($parents, $field_name, $form_state, $field_state);
+  }
+
   /**
    * Validate callback for alt and title field, if the user wants them required.
    *
diff --git a/core/modules/image/tests/src/FunctionalJavascript/ImageFieldWidgetMultipleTest.php b/core/modules/image/tests/src/FunctionalJavascript/ImageFieldWidgetMultipleTest.php
new file mode 100644
index 0000000000..84c1a1a05b
--- /dev/null
+++ b/core/modules/image/tests/src/FunctionalJavascript/ImageFieldWidgetMultipleTest.php
@@ -0,0 +1,103 @@
+<?php
+
+namespace Drupal\Tests\image\FunctionalJavascript;
+
+use Drupal\Core\Field\FieldStorageDefinitionInterface;
+use Drupal\FunctionalJavascriptTests\DrupalSelenium2Driver;
+use Drupal\FunctionalJavascriptTests\WebDriverTestBase;
+use Drupal\node\Entity\Node;
+use Drupal\Tests\image\Kernel\ImageFieldCreationTrait;
+use Drupal\Tests\TestFileCreationTrait;
+
+/**
+ * Tests the image field widget support multiple upload correctly.
+ *
+ * @group image
+ */
+class ImageFieldWidgetMultipleTest extends WebDriverTestBase {
+
+  use ImageFieldCreationTrait;
+  use TestFileCreationTrait;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected $minkDefaultDriverClass = DrupalSelenium2Driver::class;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $modules = [
+    'node',
+    'field_ui',
+    'image',
+  ];
+
+  /**
+   * Tests image widget element support multiple upload correctly.
+   */
+  public function testWidgetElementMultipleUploads() {
+    $image_factory = \Drupal::service('image.factory');
+    $file_system = \Drupal::service('file_system');
+
+    $this->drupalCreateContentType(['type' => 'article', 'name' => 'Article']);
+    $field_name = 'images';
+    $storage_settings = ['cardinality' => FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED];
+    $field_settings = ['alt_field_required' => 0];
+    $this->createImageField($field_name, 'article', $storage_settings, $field_settings);
+    $this->drupalLogin($this->drupalCreateUser(['access content', 'create article content']));
+    $this->drupalGet('node/add/article');
+    $this->xpath('//input[@name="title[0][value]"]')[0]->setValue('Test');
+
+    $images = $this->getTestFiles('image');
+    $images = array_slice($images, 0, 5);
+
+    $paths = [];
+    foreach ($images as $image) {
+      $paths[] = $file_system->realpath($image->uri);
+    }
+
+    $remote_paths = [];
+    foreach ($paths as $path) {
+      $remote_paths[] = $this->uploadFileRemotePath($path);
+    }
+
+    $multiple_field = $this->xpath('//input[@multiple]')[0];
+    $multiple_field->setValue(implode("\n", $remote_paths));
+    $this->assertSession()->waitForElementVisible('css', '[data-drupal-selector="edit-images-4-preview"]');
+    $this->getSession()->getPage()->findButton('Save')->click();
+
+    $node = Node::load(1);
+    foreach ($paths as $delta => $path) {
+      $node_image = $node->{$field_name}[$delta];
+      $original_image = $image_factory->get($path);
+      $this->assertEquals($node_image->width, $original_image->getWidth(), "Correct width of image #$delta");
+      $this->assertEquals($node_image->height, $original_image->getHeight(), "Correct height of image #$delta");
+    }
+  }
+
+  /**
+   * Uploads a file to the Selenium instance for get remote path.
+   *
+   * Copied from \Behat\Mink\Driver\Selenium2Driver::uploadFile().
+   *
+   * @param string $path
+   *   The path to the file to upload.
+   *
+   * @return string
+   *   The remote path.
+   *
+   * @todo: Remove after https://www.drupal.org/project/drupal/issues/2947517.
+   */
+  protected function uploadFileRemotePath($path) {
+    $tempFilename = tempnam('', 'WebDriverZip');
+    $archive = new \ZipArchive();
+    $archive->open($tempFilename, \ZipArchive::CREATE);
+    $archive->addFile($path, basename($path));
+    $archive->close();
+    $remotePath = $this->getSession()->getDriver()->getWebDriverSession()->file(['file' => base64_encode(file_get_contents($tempFilename))]);
+    unlink($tempFilename);
+    return $remotePath;
+  }
+
+}
