diff --git a/core/lib/Drupal/Core/Entity/ContentEntityForm.php b/core/lib/Drupal/Core/Entity/ContentEntityForm.php
index 4c741aef337b267a197d8bc305f21b75bdfc415e..92bbbae42f98ac98acef95ae7d4de75ce8441033 100644
--- a/core/lib/Drupal/Core/Entity/ContentEntityForm.php
+++ b/core/lib/Drupal/Core/Entity/ContentEntityForm.php
@@ -188,10 +188,29 @@ public function validateForm(array &$form, FormStateInterface $form_state) {
 
     $violations = $entity->validate();
 
-    // Remove violations of inaccessible fields and not edited fields.
-    $violations
-      ->filterByFieldAccess($this->currentUser())
-      ->filterByFields(array_diff(array_keys($entity->getFieldDefinitions()), $this->getEditedFieldNames($form_state)));
+    // Remove violations of inaccessible fields.
+    $violations->filterByFieldAccess($this->currentUser());
+
+    // In case a field-level submit button is clicked, for example the 'Add
+    // another item' button for multi-value fields or the 'Upload' button for a
+    // File or an Image field, make sure that we only keep violations for that
+    // specific field.
+    $edited_fields = [];
+    if ($limit_validation_errors = $form_state->getLimitValidationErrors()) {
+      foreach ($limit_validation_errors as $section) {
+        $field_name = reset($section);
+        if ($entity->hasField($field_name)) {
+          $edited_fields[] = $field_name;
+        }
+      }
+      $edited_fields = array_unique($edited_fields);
+    }
+    else {
+      $edited_fields = $this->getEditedFieldNames($form_state);
+    }
+
+    // Remove violations for fields that are not edited.
+    $violations->filterByFields(array_diff(array_keys($entity->getFieldDefinitions()), $edited_fields));
 
     $this->flagViolations($violations, $form, $form_state);
 
diff --git a/core/tests/Drupal/FunctionalTests/Entity/ContentEntityFormFieldValidationFilteringTest.php b/core/tests/Drupal/FunctionalTests/Entity/ContentEntityFormFieldValidationFilteringTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..0f17e6425b69c529382270ed5a7e14b37cabf6cb
--- /dev/null
+++ b/core/tests/Drupal/FunctionalTests/Entity/ContentEntityFormFieldValidationFilteringTest.php
@@ -0,0 +1,164 @@
+<?php
+
+namespace Drupal\FunctionalTests\Entity;
+
+use Drupal\Core\Field\FieldStorageDefinitionInterface;
+use Drupal\field\Entity\FieldConfig;
+use Drupal\field\Entity\FieldStorageConfig;
+use Drupal\Tests\BrowserTestBase;
+use Drupal\Tests\TestFileCreationTrait;
+
+/**
+ * Tests field validation filtering on content entity forms.
+ *
+ * @group Entity
+ */
+class ContentEntityFormFieldValidationFilteringTest extends BrowserTestBase {
+
+  use TestFileCreationTrait;
+
+  /**
+   * The ID of the type of the entity under test.
+   *
+   * @var string
+   */
+  protected $entityTypeId;
+
+  /**
+   * The single-valued field name being tested with the entity type.
+   *
+   * @var string
+   */
+  protected $fieldNameSingle;
+
+  /**
+   * The multi-valued field name being tested with the entity type.
+   *
+   * @var string
+   */
+  protected $fieldNameMultiple;
+
+  /**
+   * The name of the file field being tested with the entity type.
+   *
+   * @var string
+   */
+  protected $fieldNameFile;
+
+  /**
+   * {@inheritdoc}
+   */
+  public static $modules = ['entity_test', 'field_test', 'file', 'image'];
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+    $web_user = $this->drupalCreateUser(['administer entity_test content']);
+    $this->drupalLogin($web_user);
+
+    // Create two fields of field type "test_field", one with single cardinality
+    // and one with unlimited cardinality on the entity type "entity_test". It
+    // is important to use this field type because its default widget has a
+    // custom \Drupal\Core\Field\WidgetInterface::errorElement() implementation.
+    $this->entityTypeId = 'entity_test';
+    $this->fieldNameSingle = 'test_single';
+    $this->fieldNameMultiple = 'test_multiple';
+    $this->fieldNameFile = 'test_file';
+
+    FieldStorageConfig::create([
+      'field_name' => $this->fieldNameSingle,
+      'entity_type' => $this->entityTypeId,
+      'type' => 'test_field',
+      'cardinality' => 1,
+    ])->save();
+    FieldConfig::create([
+      'entity_type' => $this->entityTypeId,
+      'field_name' => $this->fieldNameSingle,
+      'bundle' => $this->entityTypeId,
+      'label' => 'Test single',
+      'required' => TRUE,
+      'translatable' => FALSE,
+    ])->save();
+
+    FieldStorageConfig::create([
+      'field_name' => $this->fieldNameMultiple,
+      'entity_type' => $this->entityTypeId,
+      'type' => 'test_field',
+      'cardinality' => FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED,
+    ])->save();
+    FieldConfig::create([
+      'entity_type' => $this->entityTypeId,
+      'field_name' => $this->fieldNameMultiple,
+      'bundle' => $this->entityTypeId,
+      'label' => 'Test multiple',
+      'translatable' => FALSE,
+    ])->save();
+
+    // Also create a file field to test its '#limit_validation_errors'
+    // implementation.
+    FieldStorageConfig::create([
+      'field_name' => $this->fieldNameFile,
+      'entity_type' => $this->entityTypeId,
+      'type' => 'file',
+      'cardinality' => 1,
+    ])->save();
+    FieldConfig::create([
+      'entity_type' => $this->entityTypeId,
+      'field_name' => $this->fieldNameFile,
+      'bundle' => $this->entityTypeId,
+      'label' => 'Test file',
+      'translatable' => FALSE,
+    ])->save();
+
+
+    entity_get_form_display($this->entityTypeId, $this->entityTypeId, 'default')
+      ->setComponent($this->fieldNameSingle, ['type' => 'test_field_widget'])
+      ->setComponent($this->fieldNameMultiple, ['type' => 'test_field_widget'])
+      ->setComponent($this->fieldNameFile, ['type' => 'file_generic'])
+      ->save();
+  }
+
+  /**
+   * Tests field widgets with #limit_validation_errors.
+   */
+  public function testFieldWidgetsWithLimitedValidationErrors() {
+    $assert_session = $this->assertSession();
+    $this->drupalGet($this->entityTypeId . '/add');
+
+    // The 'Test multiple' field is the only multi-valued field in the form, so
+    // try to add a new item for it. This tests the '#limit_validation_errors'
+    // property set by \Drupal\Core\Field\WidgetBase::formMultipleElements().
+    $assert_session->elementsCount('css', 'div#edit-test-multiple-wrapper div.form-type-textfield input', 1);
+    $this->drupalPostForm(NULL, [], 'Add another item');
+    $assert_session->elementsCount('css', 'div#edit-test-multiple-wrapper div.form-type-textfield input', 2);
+
+    // Now try to upload a file. This tests the '#limit_validation_errors'
+    // property set by
+    // \Drupal\file\Plugin\Field\FieldWidget\FileWidget::process().
+    $text_file = current($this->getTestFiles('text'));
+    $edit = [
+      'files[test_file_0]' => drupal_realpath($text_file->uri)
+    ];
+    $assert_session->elementNotExists('css', 'input#edit-test-file-0-remove-button');
+    $this->drupalPostForm(NULL, $edit, 'Upload');
+    $assert_session->elementExists('css', 'input#edit-test-file-0-remove-button');
+
+    // Make the 'Test multiple' field required and check that adding another
+    // item throws a validation error.
+    $field_config = FieldConfig::loadByName($this->entityTypeId, $this->entityTypeId, $this->fieldNameMultiple);
+    $field_config->setRequired(TRUE);
+    $field_config->save();
+
+    $this->drupalPostForm($this->entityTypeId . '/add', [], 'Add another item');
+    $assert_session->pageTextContains('Test multiple (value 1) field is required.');
+
+    // Check that saving the form without entering any value for the required
+    // field still throws the proper validation errors.
+    $this->drupalPostForm(NULL, [], 'Save');
+    $assert_session->pageTextContains('Test single field is required.');
+    $assert_session->pageTextContains('Test multiple (value 1) field is required.');
+  }
+
+}