diff --git a/core/lib/Drupal/Core/Render/Element/Checkboxes.php b/core/lib/Drupal/Core/Render/Element/Checkboxes.php
index cdf0554873253d3b93e6acb221861d35d08ddfbd..8d6919821f188d1c7dd0498e08c8252e61342913 100644
--- a/core/lib/Drupal/Core/Render/Element/Checkboxes.php
+++ b/core/lib/Drupal/Core/Render/Element/Checkboxes.php
@@ -73,12 +73,19 @@ public static function processCheckboxes(&$element, FormStateInterface $form_sta
         // sub-elements.
         $weight += 0.001;
 
+        // Only enabled checkboxes receive their values from the form
+        // submission, the disabled checkboxes use their default value.
+        $default_value = NULL;
+        if (isset($value[$key]) || (!empty($element[$key]['#disabled']) && in_array($key, $element['#default_value'], TRUE))) {
+          $default_value = $key;
+        }
+
         $element += [$key => []];
         $element[$key] += [
           '#type' => 'checkbox',
           '#title' => $choice,
           '#return_value' => $key,
-          '#default_value' => isset($value[$key]) ? $key : NULL,
+          '#default_value' => $default_value,
           '#attributes' => $element['#attributes'],
           '#ajax' => $element['#ajax'] ?? NULL,
           // Errors should only be shown on the parent checkboxes element.
@@ -115,6 +122,17 @@ public static function valueCallback(&$element, $input, FormStateInterface $form
           unset($input[$key]);
         }
       }
+
+      // Because the disabled checkboxes don't receive their input from the
+      // form submission, we use their default value.
+      if (!empty($element['#default_value'])) {
+        foreach ($element['#default_value'] as $key) {
+          if (!empty($element[$key]['#disabled'])) {
+            $input[$key] = $key;
+          }
+        }
+      }
+
       return array_combine($input, $input);
     }
     else {
diff --git a/core/modules/system/tests/modules/form_test/src/Form/FormTestDisabledElementsForm.php b/core/modules/system/tests/modules/form_test/src/Form/FormTestDisabledElementsForm.php
index eef9efae5c853a04ae54efc019f88c6883e90085..bd8d2841e0938713296b6aa75b59a462baa92200 100644
--- a/core/modules/system/tests/modules/form_test/src/Form/FormTestDisabledElementsForm.php
+++ b/core/modules/system/tests/modules/form_test/src/Form/FormTestDisabledElementsForm.php
@@ -36,7 +36,7 @@ public function buildForm(array $form, FormStateInterface $form_state) {
       ];
     }
 
-    // Multiple values option elements.
+    // Multiple values option elements, disabled as a whole.
     foreach (['checkboxes', 'select'] as $type) {
       $form[$type . '_multiple'] = [
         '#type' => $type,
@@ -54,6 +54,34 @@ public function buildForm(array $form, FormStateInterface $form_state) {
       ];
     }
 
+    // Multiple values option elements, only single options disabled.
+    $form['checkboxes_single_select'] = [
+      '#type' => 'checkboxes',
+      '#title' => 'checkboxes (multiple)',
+      '#options' => [
+        'test_1' => 'Test 1',
+        'test_2' => 'Test 2',
+      ],
+      '#multiple' => TRUE,
+      '#default_value' => ['test_2' => 'test_2'],
+      'test_1' => [
+        '#disabled' => TRUE,
+      ],
+    ];
+    $form['checkboxes_single_unselect'] = [
+      '#type' => 'checkboxes',
+      '#title' => 'checkboxes (multiple)',
+      '#options' => [
+        'test_1' => 'Test 1',
+        'test_2' => 'Test 2',
+      ],
+      '#multiple' => TRUE,
+      '#default_value' => ['test_2' => 'test_2'],
+      'test_2' => [
+        '#disabled' => TRUE,
+      ],
+    ];
+
     // Single values option elements.
     foreach (['radios', 'select'] as $type) {
       $form[$type . '_single'] = [
diff --git a/core/modules/system/tests/src/Functional/Form/FormTest.php b/core/modules/system/tests/src/Functional/Form/FormTest.php
index 471f30390496d56d7da8ba2fca4e647f65a28833..505bc76dbce0dcb56bad9c36cbdf4ff63d19a0ff 100644
--- a/core/modules/system/tests/src/Functional/Form/FormTest.php
+++ b/core/modules/system/tests/src/Functional/Form/FormTest.php
@@ -769,7 +769,7 @@ public function testDisabledElements() {
     // All the elements should be marked as disabled, including the ones below
     // the disabled container.
     $actual_count = count($disabled_elements);
-    $expected_count = 42;
+    $expected_count = 44;
     $this->assertEquals($expected_count, $actual_count, new FormattableMarkup('Found @actual elements with disabled property (expected @expected).', ['@actual' => count($disabled_elements), '@expected' => $expected_count]));
 
     // Mink does not "see" hidden elements, so we need to set the value of the
@@ -803,7 +803,7 @@ public function assertFormValuesDefault(array $values, array $form): void {
           $expected_value = $form[$key]['#default_value'];
         }
 
-        if ($key == 'checkboxes_multiple') {
+        if (in_array($key, ['checkboxes_multiple', 'checkboxes_single_select', 'checkboxes_single_unselect'], TRUE)) {
           // Checkboxes values are not filtered out.
           $values[$key] = array_filter($values[$key]);
         }