diff --git a/core/lib/Drupal/Core/Render/Element/MachineName.php b/core/lib/Drupal/Core/Render/Element/MachineName.php
index 9e0532646861ca54931f8095ff5ef41760f10075..555a044c0e29f56cfd4db0d896141e179a44d954 100644
--- a/core/lib/Drupal/Core/Render/Element/MachineName.php
+++ b/core/lib/Drupal/Core/Render/Element/MachineName.php
@@ -44,7 +44,8 @@
  *   - error: (optional) A custom form error message string to show, if the
  *     machine name contains disallowed characters.
  *   - standalone: (optional) Whether the live preview should stay in its own
- *     form element rather than in the suffix of the source element. Defaults
+ *     form element rather than in the suffix of the source element. The source
+ *     element must appear in the form structure before this element. Defaults
  *     to FALSE.
  * - #maxlength: (optional) Maximum allowed length of the machine name. Defaults
  *   to 64.
@@ -183,6 +184,13 @@ public static function processMachineName(&$element, FormStateInterface $form_st
       return $element;
     }
 
+    // The source element must be defined before the machine name element.
+    if (!isset($source['#id'])) {
+      $element_parents = implode('][', $element['#array_parents']);
+      $source_parents = implode('][', $element['#machine_name']['source']);
+      throw new \LogicException(sprintf('The machine name element "%s" is defined before the source element "%s", it must be defined after or the source element must specify an id.', $element_parents, $source_parents));
+    }
+
     $suffix_id = $source['#id'] . '-machine-name-suffix';
     $element['#machine_name']['suffix'] = '#' . $suffix_id;
 
diff --git a/core/tests/Drupal/KernelTests/Core/Render/Element/MachineNameTest.php b/core/tests/Drupal/KernelTests/Core/Render/Element/MachineNameTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..74c3e95a963b5b4794f16e6c651050deefa62d28
--- /dev/null
+++ b/core/tests/Drupal/KernelTests/Core/Render/Element/MachineNameTest.php
@@ -0,0 +1,74 @@
+<?php
+
+namespace Drupal\KernelTests\Core\Render\Element;
+
+use Drupal\Core\Form\FormInterface;
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\KernelTests\KernelTestBase;
+
+/**
+ * @coversDefaultClass \Drupal\Core\Render\Element\MachineName
+ * @group Render
+ */
+class MachineNameTest extends KernelTestBase implements FormInterface {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $modules = ['system'];
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getFormId() {
+    return __CLASS__;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function buildForm(array $form, FormStateInterface $form_state) {
+    $element = [
+      '#id' => 'test',
+      '#type' => 'machine_name',
+      '#machine_name' => [
+        'source' => [
+          'test_source',
+        ],
+      ],
+      '#name' => 'test_machine_name',
+      '#default_value' => NULL,
+    ];
+
+    $complete_form = [
+      'test_machine_name' => $element,
+      'test_source' => [
+        '#type' => 'textfield',
+      ],
+    ];
+    return $complete_form;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function validateForm(array &$form, FormStateInterface $form_state) {
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function submitForm(array &$form, FormStateInterface $form_state) {
+  }
+
+  /**
+   * Tests the order of the machine name field and the source.
+   */
+  public function testMachineNameOrderException() {
+    $this->expectException(\LogicException::class);
+    $this->expectErrorMessage('The machine name element "test_machine_name" is defined before the source element "test_source", it must be defined after or the source element must specify an id.');
+    $form = \Drupal::formBuilder()->getForm($this);
+    $this->render($form);
+  }
+
+}