diff --git a/core/modules/media_library/src/Plugin/Field/FieldWidget/MediaLibraryWidget.php b/core/modules/media_library/src/Plugin/Field/FieldWidget/MediaLibraryWidget.php
index 419cf66174..558dbfca35 100644
--- a/core/modules/media_library/src/Plugin/Field/FieldWidget/MediaLibraryWidget.php
+++ b/core/modules/media_library/src/Plugin/Field/FieldWidget/MediaLibraryWidget.php
@@ -320,6 +320,7 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen
       '#attached' => [
         'library' => ['media_library/widget'],
       ],
+      '#element_validate' => [[static::class, 'validateMediaWidget']],
     ];
 
     // When the list of allowed types in the field configuration is null,
@@ -541,8 +542,14 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen
       ],
       '#validate' => [[static::class, 'validateItems']],
       '#submit' => [[static::class, 'addItems']],
-      // Prevent errors in other widgets from preventing updates.
-      '#limit_validation_errors' => $limit_validation_errors,
+      // If no media has been uploaded ($referenced_entities), suppress
+      // validation errors in the widget entirely. This prevents the
+      // widget-level validation from triggering required fields errors before
+      // media has been uploaded.
+      // If media is present, check for errors within this widget, but suppress
+      // errors in all other widgets.
+      '#limit_validation_errors' => !empty($referenced_entities) ? $limit_validation_errors : [],
+
     ];
 
     return $element;
@@ -744,6 +751,59 @@ public static function openMediaLibrary(array $form, FormStateInterface $form_st
       ->addCommand(new OpenModalDialogCommand($dialog_options['title'], $library_ui, $dialog_options));
   }
 
+  /**
+   * Validation checks specific to the Media Library widget in a parent form.
+   *
+   * @param array $element
+   *   The form element.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The form state.
+   * @param array $form
+   *   The form array.
+   */
+  public static function validateMediaWidget(array $element, FormStateInterface $form_state, array $form) {
+    // If a remove button triggered submit, this validation isn't needed.
+    if (in_array([static::class, 'removeItem'], $form_state->getSubmitHandlers())) {
+      return;
+    }
+
+    $media = static::getNewMediaItems($element, $form_state);
+
+    // Trigger error if the field is required and no media is present.
+    // Although the Form API's default validation would also catch this, the
+    // validation error message is too vague, so a more precise one is
+    // provided here.
+    //
+    // Note that the empty() is checking $element['selection'][0] and not
+    // $element['selection'] because $element['selection'] is a complete render
+    // array. Specifically checking for $element['selection'][0] checks if a
+    // value is present.
+    if (empty($media) && empty($element['selection'][0]) && !empty($element['#required'])) {
+      $field_name = $element['#title'];
+      $form_state->setError($element, \Drupal::translation()->translate('The field @field_name requires an item from the media library.',
+        ['@field_name' => $field_name]));
+      return;
+    }
+
+    $field_state = static::getFieldState($element, $form_state);
+
+    // After media is uploaded, validation of this field occurs on the widget
+    // level (the validation in this method). The field is then additionally
+    // validated by rules applied at the parent form level.
+    // The validation from the parent form can occur before uploaded media is
+    // added to the field. If the field is required, this can result in a
+    // validation error due to the parent form checking for the presence of
+    // required media before it's been transferred to the field.
+    // To avoid this error, newly added media is added to the field prior to
+    // parent form validation.
+    if (count($field_state['items']) === 0 && !empty($media) && !empty($element['#required'])) {
+      $field_state['items'] = array_filter(array_map(function ($media_item) {
+        return $media_item->access('view') ? ['target_id' => $media_item->id()] : NULL;
+      }, $media));
+    }
+    static::setFieldState($element, $form_state, $field_state);
+  }
+
   /**
    * Validates that newly selected items can be added to the widget.
    *
diff --git a/core/modules/media_library/tests/modules/media_library_test_widget/config/schema/media_library_test_widget.schema.yml b/core/modules/media_library/tests/modules/media_library_test_widget/config/schema/media_library_test_widget.schema.yml
new file mode 100644
index 0000000000..81186253e1
--- /dev/null
+++ b/core/modules/media_library/tests/modules/media_library_test_widget/config/schema/media_library_test_widget.schema.yml
@@ -0,0 +1,10 @@
+field.widget.settings.media_library_inception_widget:
+  type: mapping
+  label: 'Media library inception widget settings'
+  mapping:
+    media_types:
+      type: sequence
+      label: 'Allowed media types, in display order'
+      sequence:
+        type: string
+        label: 'Media type ID'
diff --git a/core/modules/media_library/tests/modules/media_library_test_widget/media_library_test_widget.info.yml b/core/modules/media_library/tests/modules/media_library_test_widget/media_library_test_widget.info.yml
new file mode 100644
index 0000000000..fe6cac86a5
--- /dev/null
+++ b/core/modules/media_library/tests/modules/media_library_test_widget/media_library_test_widget.info.yml
@@ -0,0 +1,9 @@
+name: 'Media Library test widget'
+type: module
+description: 'Test widget that has a nested media library widget'
+package: Testing
+core: 8.x
+dependencies:
+  - drupal:image
+  - drupal:media_library
+  - drupal:media_test_source
diff --git a/core/modules/media_library/tests/modules/media_library_test_widget/src/Plugin/Field/FieldWidget/MediaLibraryInceptionWidget.php b/core/modules/media_library/tests/modules/media_library_test_widget/src/Plugin/Field/FieldWidget/MediaLibraryInceptionWidget.php
new file mode 100644
index 0000000000..8bb08c415e
--- /dev/null
+++ b/core/modules/media_library/tests/modules/media_library_test_widget/src/Plugin/Field/FieldWidget/MediaLibraryInceptionWidget.php
@@ -0,0 +1,56 @@
+<?php
+
+namespace Drupal\media_library_test_widget\Plugin\Field\FieldWidget;
+
+use Drupal\Core\Field\FieldItemListInterface;
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Entity\Entity\EntityFormDisplay;
+use Drupal\media_library\Plugin\Field\FieldWidget\MediaLibraryWidget;
+
+/**
+ * Plugin implementation of the 'media_library_inception_widget' widget.
+ *
+ * This widget is used to simulate the media library widget nested inside
+ * another widget that performs validation of required fields before there is
+ * an opportunity to add media.
+ *
+ * @FieldWidget(
+ *   id = "media_library_inception_widget",
+ *   label = @Translation("Media library inception widget"),
+ *   description = @Translation("Puts a widget in a widget for testing purposes"),
+ *   field_types = {
+ *     "entity_reference"
+ *   },
+ *   multiple_values = TRUE,
+ * )
+ */
+class MediaLibraryInceptionWidget extends MediaLibraryWidget {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
+    $element['#element_validate'][] = [$this, 'elementValidate'];
+    return parent::formElement($items, $delta, $element, $form, $form_state);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function elementValidate($element, FormStateInterface $form_state, $form) {
+    $field_name = $element['#field_name'];
+    $entity = $form_state->getFormObject()->getEntity();
+    $input = $form_state->getUserInput();
+    if (!empty($input['_triggering_element_name']) && strpos($input['_triggering_element_name'], 'media-library-update') !== FALSE) {
+      // This will validate a required field before an upload is completed.
+      $display = EntityFormDisplay::collectRenderDisplay($entity, 'edit');
+      $display->extractFormValues($entity, $form, $form_state);
+      $display->validateFormValues($entity, $form, $form_state);
+    }
+    $form_value = $form_state->getValue($field_name);
+    if (!empty($form_value['media_library_selection'])) {
+      $entity->set($field_name, $form_value['media_library_selection']);
+    }
+  }
+
+}
diff --git a/core/modules/media_library/tests/src/FunctionalJavascript/EmbeddedFormWidgetTest.php b/core/modules/media_library/tests/src/FunctionalJavascript/EmbeddedFormWidgetTest.php
new file mode 100644
index 0000000000..7488e4cbe0
--- /dev/null
+++ b/core/modules/media_library/tests/src/FunctionalJavascript/EmbeddedFormWidgetTest.php
@@ -0,0 +1,107 @@
+<?php
+
+namespace Drupal\Tests\media_library\FunctionalJavascript;
+
+use Drupal\field\Entity\FieldConfig;
+use Drupal\field\Entity\FieldStorageConfig;
+use Drupal\FunctionalJavascriptTests\WebDriverTestBase;
+use Drupal\Tests\TestFileCreationTrait;
+
+/**
+ * Tests media widget nested inside another widget.
+ *
+ * @group media_library
+ */
+class EmbeddedFormWidgetTest extends WebDriverTestBase {
+
+  use TestFileCreationTrait;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $modules = [
+    'media_library',
+    'media_library_test',
+    'media_library_test_widget',
+  ];
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+
+    $display_repository = $this->container->get('entity_display.repository');
+
+    FieldStorageConfig::create([
+      'field_name' => 'media_image_field',
+      'entity_type' => 'node',
+      'type' => 'entity_reference',
+      'settings' => [
+        'target_type' => 'media',
+        'required' => TRUE,
+      ],
+    ])->save();
+
+    FieldConfig::create([
+      'label' => 'A Media Image Field',
+      'field_name' => 'media_image_field',
+      'entity_type' => 'node',
+      'bundle' => 'basic_page',
+      'field_type' => 'entity_reference',
+      'required' => TRUE,
+      'settings' => [
+        'handler_settings' => [
+          'target_bundles' => [
+            'type_three' => 'type_three',
+          ],
+        ],
+      ],
+    ])->save();
+
+    $display_repository->getFormDisplay('node', 'basic_page')
+      ->setComponent('media_image_field', [
+        'type' => 'media_library_inception_widget',
+        'region' => 'content',
+        'settings' => [
+          'media_types' => ['type_three'],
+        ],
+      ])
+      ->save();
+
+    $user = $this->drupalCreateUser([
+      'access content',
+      'access media overview',
+      'edit own basic_page content',
+      'create basic_page content',
+      'create media',
+      'view media',
+    ]);
+    $this->drupalLogin($user);
+  }
+
+  /**
+   * Test media inside another widget that validates too enthusiastically.
+   */
+  public function testEmbeddedFormWidget() {
+    $page = $this->getSession()->getPage();
+    $assert_session = $this->assertSession();
+
+    foreach ($this->getTestFiles('image') as $image) {
+      $extension = pathinfo($image->filename, PATHINFO_EXTENSION);
+      if ($extension === 'jpg') {
+        $jpg_image = $image;
+      }
+    }
+
+    $this->drupalGet('node/add/basic_page');
+    $assert_session->elementExists('css', '.media-library-open-button[name="media_image_field-media-library-open-button"]')->click();
+    $this->assertTrue($assert_session->waitForText('Add or select media'));
+    $page->attachFileToField('Add file', $this->container->get('file_system')->realpath($jpg_image->uri));
+    $this->assertTrue($assert_session->waitForText('Alternative text'));
+    $page->fillField('Alternative text', $this->randomString());
+    $assert_session->elementExists('css', '.ui-dialog-buttonpane')->pressButton('Save and insert');
+    $this->assertTrue($assert_session->waitForText($jpg_image->filename));
+  }
+
+}
