diff --git a/core/lib/Drupal/Core/Render/Element/File.php b/core/lib/Drupal/Core/Render/Element/File.php
index c909b926deaf20cfd0385cf59ee2c682ff8852b5..315817319862c8251f68c69f7a2f1f6fb4e1f160 100644
--- a/core/lib/Drupal/Core/Render/Element/File.php
+++ b/core/lib/Drupal/Core/Render/Element/File.php
@@ -15,6 +15,10 @@
  * - #multiple: A Boolean indicating whether multiple files may be uploaded.
  * - #size: The size of the file input element in characters.
  *
+ * The value of this form element will always be an array of
+ * \Symfony\Component\HttpFoundation\File\UploadedFile objects, regardless of
+ * whether #multiple is TRUE or FALSE
+ *
  * @FormElement("file")
  */
 class File extends FormElement {
@@ -36,6 +40,9 @@ public function getInfo() {
       ],
       '#theme' => 'input__file',
       '#theme_wrappers' => ['form_element'],
+      '#value_callback' => [
+        [$class, 'valueCallback'],
+      ],
     ];
   }
 
@@ -72,4 +79,23 @@ public static function preRenderFile($element) {
     return $element;
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public static function valueCallback(&$element, $input, FormStateInterface $form_state) {
+    if ($input === FALSE) {
+      return NULL;
+    }
+    $parents = $element['#parents'];
+    $element_name = array_shift($parents);
+    $uploaded_files = \Drupal::request()->files->get('files', []);
+    $uploaded_file = $uploaded_files[$element_name] ?? NULL;
+    if ($uploaded_file) {
+      // Cast this to an array so that the structure is consistent regardless of
+      // whether #value is set or not.
+      return (array) $uploaded_file;
+    }
+    return NULL;
+  }
+
 }
diff --git a/core/modules/file/tests/file_test/file_test.routing.yml b/core/modules/file/tests/file_test/file_test.routing.yml
index 0505615a4e5a274d6ad2ff2597ae4c027a0d01d4..20af642f92a5f1373d5fc27112e1147b71fa6124 100644
--- a/core/modules/file/tests/file_test/file_test.routing.yml
+++ b/core/modules/file/tests/file_test/file_test.routing.yml
@@ -10,3 +10,9 @@ file.save_upload_from_form_test:
     _form: '\Drupal\file_test\Form\FileTestSaveUploadFromForm'
   requirements:
     _access: 'TRUE'
+file.required_test:
+  path: '/file-test/upload_required'
+  defaults:
+    _form: '\Drupal\file_test\Form\FileRequiredTestForm'
+  requirements:
+    _access: 'TRUE'
diff --git a/core/modules/file/tests/file_test/src/Form/FileRequiredTestForm.php b/core/modules/file/tests/file_test/src/Form/FileRequiredTestForm.php
new file mode 100644
index 0000000000000000000000000000000000000000..c6dca9b0f6892e2615b0b958bcb0fc2f2cabbda6
--- /dev/null
+++ b/core/modules/file/tests/file_test/src/Form/FileRequiredTestForm.php
@@ -0,0 +1,28 @@
+<?php
+
+namespace Drupal\file_test\Form;
+
+use Drupal\Core\Form\FormStateInterface;
+
+/**
+ * File required test form class.
+ */
+class FileRequiredTestForm extends FileTestForm {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getFormId() {
+    return '_file_required_test_form';
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function buildForm(array $form, FormStateInterface $form_state) {
+    $form = parent::buildForm($form, $form_state);
+    $form['file_test_upload']['#required'] = TRUE;
+    return $form;
+  }
+
+}
diff --git a/core/modules/file/tests/src/Functional/SaveUploadTest.php b/core/modules/file/tests/src/Functional/SaveUploadTest.php
index 3fa9f3d8f76f0f1a0578655aa75ad39d4235bd03..4a70d2d1c5a6de1315e92096979650d45c58c422 100644
--- a/core/modules/file/tests/src/Functional/SaveUploadTest.php
+++ b/core/modules/file/tests/src/Functional/SaveUploadTest.php
@@ -732,4 +732,26 @@ public function testInvalidUtf8FilenameUpload() {
     $this->assertFileDoesNotExist('temporary://' . $filename);
   }
 
+  /**
+   * Tests the file_save_upload() function when the field is required.
+   */
+  public function testRequired() {
+    // Reset the hook counters to get rid of the 'load' we just called.
+    file_test_reset();
+
+    // Confirm the field is required.
+    $this->drupalGet('file-test/upload_required');
+    $this->submitForm([], 'Submit');
+    $this->assertSession()->statusCodeEquals(200);
+    $this->assertSession()->responseContains('field is required');
+
+    // Confirm that uploading another file works.
+    $image = current($this->drupalGetTestFiles('image'));
+    $edit = ['files[file_test_upload]' => \Drupal::service('file_system')->realpath($image->uri)];
+    $this->drupalGet('file-test/upload_required');
+    $this->submitForm($edit, 'Submit');
+    $this->assertSession()->statusCodeEquals(200);
+    $this->assertSession()->responseContains('You WIN!');
+  }
+
 }
diff --git a/core/modules/system/src/Form/ThemeSettingsForm.php b/core/modules/system/src/Form/ThemeSettingsForm.php
index 00d6b28c71e93d30c833bd28823d3f966c24c776..3d044f5c28cc0a27728f2036537f32fb1ee083a2 100644
--- a/core/modules/system/src/Form/ThemeSettingsForm.php
+++ b/core/modules/system/src/Form/ThemeSettingsForm.php
@@ -234,7 +234,6 @@ public function buildForm(array $form, FormStateInterface $form_state, $theme =
       $form['logo']['settings']['logo_upload'] = [
         '#type' => 'file',
         '#title' => $this->t('Upload logo image'),
-        '#maxlength' => 40,
         '#description' => $this->t("If you don't have direct file access to the server, use this field to upload your logo."),
         '#upload_validators' => [
           'file_validate_is_image' => [],