diff --git a/core/lib/Drupal/Core/Entity/ContentEntityStorageBase.php b/core/lib/Drupal/Core/Entity/ContentEntityStorageBase.php
index e92930a..610cda4 100644
--- a/core/lib/Drupal/Core/Entity/ContentEntityStorageBase.php
+++ b/core/lib/Drupal/Core/Entity/ContentEntityStorageBase.php
@@ -82,7 +82,7 @@ protected function doCreate(array $values) {
   /**
    * {@inheritdoc}
    */
-  public function createWithSampleValues($bundle = FALSE, array $values = []) {
+  public function createWithSampleValues($bundle = FALSE, array $values = [], $required_only = FALSE) {
     // ID and revision should never have sample values generated for them.
     $forbidden_keys = [
       $this->entityType->getKey('id'),
@@ -90,23 +90,22 @@ public function createWithSampleValues($bundle = FALSE, array $values = []) {
     if ($revision_key = $this->entityType->getKey('revision')) {
       $forbidden_keys[] = $revision_key;
     }
-    if ($bundle_key = $this->entityType->getKey('bundle')) {
-      if (!$bundle) {
-        throw new EntityStorageException("No entity bundle was specified");
-      }
-      if (!array_key_exists($bundle, $this->entityManager->getBundleInfo($this->entityTypeId))) {
-        throw new EntityStorageException(sprintf("Missing entity bundle. The \"%s\" bundle does not exist", $bundle));
-      }
+    if ($bundle && $bundle_key = $this->entityType->getKey('bundle')) {
       $values[$bundle_key] = $bundle;
-      // Bundle is already set
-      $forbidden_keys[] = $bundle_key;
+    }
+    if ($published_key = $this->entityType->getKey('published')) {
+      $values[$published_key] = TRUE;
+    }
+    if ($status_key = $this->entityType->getKey('status')) {
+      $values[$status_key] = TRUE;
     }
     // Forbid sample generation on any keys whose values were submitted.
     $forbidden_keys = array_merge($forbidden_keys, array_keys($values));
     /** @var \Drupal\Core\Entity\FieldableEntityInterface $entity */
     $entity = $this->create($values);
     foreach ($entity as $field_name => $value) {
-      if (!in_array($field_name, $forbidden_keys, TRUE)) {
+      $definition = $entity->getFieldDefinition($field_name);
+      if (!in_array($field_name, $forbidden_keys, TRUE) && (!$required_only || ($definition && $definition->isRequired()))) {
         $entity->get($field_name)->generateSampleItems();
       }
     }
diff --git a/core/lib/Drupal/Core/Entity/ContentEntityStorageInterface.php b/core/lib/Drupal/Core/Entity/ContentEntityStorageInterface.php
index eb979c7..cd79530 100644
--- a/core/lib/Drupal/Core/Entity/ContentEntityStorageInterface.php
+++ b/core/lib/Drupal/Core/Entity/ContentEntityStorageInterface.php
@@ -23,7 +23,6 @@
    */
   public function createTranslation(ContentEntityInterface $entity, $langcode, array $values = []);
 
-
   /**
    * Creates an entity with sample field values.
    *
@@ -31,6 +30,9 @@ public function createTranslation(ContentEntityInterface $entity, $langcode, arr
    *   (optional) The entity bundle.
    * @param array $values
    *   (optional) Any default values to use during generation.
+   * @param bool $required_only
+   *   (optional) If TRUE, only create sample values for required fields.
+   *   Defaults to FALSE.
    *
    * @return \Drupal\Core\Entity\FieldableEntityInterface
    *   A fieldable content entity.
@@ -38,6 +40,6 @@ public function createTranslation(ContentEntityInterface $entity, $langcode, arr
    * @throws \Drupal\Core\Entity\EntityStorageException
    *   Thrown if the bundle does not exist or was needed but not specified.
    */
-  public function createWithSampleValues($bundle = FALSE, array $values = []);
+  public function createWithSampleValues($bundle = FALSE, array $values = [], $required_only = FALSE);
 
 }
diff --git a/core/lib/Drupal/Core/Entity/KeyValueStore/KeyValueContentEntityStorage.php b/core/lib/Drupal/Core/Entity/KeyValueStore/KeyValueContentEntityStorage.php
index b3fc12d..9510963 100644
--- a/core/lib/Drupal/Core/Entity/KeyValueStore/KeyValueContentEntityStorage.php
+++ b/core/lib/Drupal/Core/Entity/KeyValueStore/KeyValueContentEntityStorage.php
@@ -21,6 +21,7 @@ public function createTranslation(ContentEntityInterface $entity, $langcode, arr
   /**
    * {@inheritdoc}
    */
-  public function createWithSampleValues($bundle = FALSE, array $values = []) {}
+  public function createWithSampleValues($bundle = FALSE, array $values = [], $required_only = FALSE) {
+  }
 
 }
diff --git a/core/modules/content_moderation/src/StateTransitionValidation.php b/core/modules/content_moderation/src/StateTransitionValidation.php
index fc09e5e..2a06229 100644
--- a/core/modules/content_moderation/src/StateTransitionValidation.php
+++ b/core/modules/content_moderation/src/StateTransitionValidation.php
@@ -40,6 +40,10 @@ public function __construct(ModerationInformationInterface $moderation_info) {
    */
   public function getValidTransitions(ContentEntityInterface $entity, AccountInterface $user) {
     $workflow = $this->moderationInfo->getWorkflowForEntity($entity);
+    if (!$workflow) {
+      return [];
+    }
+
     $current_state = $entity->moderation_state->value ? $workflow->getTypePlugin()->getState($entity->moderation_state->value) : $workflow->getTypePlugin()->getInitialState($entity);
 
     return array_filter($current_state->getTransitions(), function(Transition $transition) use ($workflow, $user) {
diff --git a/core/modules/content_translation/content_translation.module b/core/modules/content_translation/content_translation.module
index 8dbd170..869f982 100644
--- a/core/modules/content_translation/content_translation.module
+++ b/core/modules/content_translation/content_translation.module
@@ -5,6 +5,7 @@
  * Allows entities to be translated into different languages.
  */
 
+use Drupal\content_translation\Form\ContentTranslationDeleteForm;
 use Drupal\Core\Access\AccessResult;
 use Drupal\Core\Entity\ContentEntityFormInterface;
 use Drupal\Core\Entity\ContentEntityInterface;
@@ -128,9 +129,6 @@ function content_translation_entity_type_alter(array &$entity_types) {
       if (!$entity_type->get('content_translation_metadata')) {
         $entity_type->set('content_translation_metadata', 'Drupal\content_translation\ContentTranslationMetadataWrapper');
       }
-      if (!$entity_type->getFormClass('content_translation_deletion')) {
-        $entity_type->setFormClass('content_translation_deletion', '\Drupal\content_translation\Form\ContentTranslationDeleteForm');
-      }
 
       $translation = $entity_type->get('translation');
       if (!$translation || !isset($translation['content_translation'])) {
@@ -151,6 +149,10 @@ function content_translation_entity_type_alter(array &$entity_types) {
         $translation['content_translation'] += [
           'access_callback' => 'content_translation_translate_access',
         ];
+
+        if (!$entity_type->getFormClass('content_translation_deletion')) {
+          $entity_type->setFormClass('content_translation_deletion', ContentTranslationDeleteForm::class);
+        }
       }
       $entity_type->set('translation', $translation);
     }
diff --git a/core/modules/image/src/Form/ImageStyleEditForm.php b/core/modules/image/src/Form/ImageStyleEditForm.php
index 53d40da..cdd156f 100644
--- a/core/modules/image/src/Form/ImageStyleEditForm.php
+++ b/core/modules/image/src/Form/ImageStyleEditForm.php
@@ -55,11 +55,13 @@ public function form(array $form, FormStateInterface $form_state) {
     $form['#attached']['library'][] = 'image/admin';
 
     // Show the thumbnail preview.
-    $preview_arguments = ['#theme' => 'image_style_preview', '#style' => $this->entity];
     $form['preview'] = [
       '#type' => 'item',
       '#title' => $this->t('Preview'),
-      '#markup' => \Drupal::service('renderer')->render($preview_arguments),
+      'image_style_preview' => [
+        '#theme' => 'image_style_preview',
+        '#style' => $this->entity,
+      ],
       // Render preview above parent elements.
       '#weight' => -5,
     ];
diff --git a/core/modules/language/src/Element/LanguageConfiguration.php b/core/modules/language/src/Element/LanguageConfiguration.php
index 6920b0d..89ef5f9 100644
--- a/core/modules/language/src/Element/LanguageConfiguration.php
+++ b/core/modules/language/src/Element/LanguageConfiguration.php
@@ -34,7 +34,7 @@ public static function processLanguageConfiguration(&$element, FormStateInterfac
     $options = isset($element['#options']) ? $element['#options'] : [];
     // Avoid validation failure since we are moving the '#options' key in the
     // nested 'language' select element.
-    unset($element['#options']);
+    unset($element['#options'], $element['#type']);
     /** @var \Drupal\language\Entity\ContentLanguageSettings $default_config */
     $default_config = $element['#default_value'];
     $element['langcode'] = [
diff --git a/core/modules/language/src/Form/ContentLanguageSettingsForm.php b/core/modules/language/src/Form/ContentLanguageSettingsForm.php
index 38aaffa..e248749 100644
--- a/core/modules/language/src/Form/ContentLanguageSettingsForm.php
+++ b/core/modules/language/src/Form/ContentLanguageSettingsForm.php
@@ -117,6 +117,8 @@ public function buildForm(array $form, FormStateInterface $form_state) {
         $form['settings'][$entity_type_id][$bundle]['settings'] = [
           '#type' => 'item',
           '#label' => $bundle_info['label'],
+          '#title' => $bundle_info['label'],
+          '#title_display' => 'invisible',
           'language' => [
             '#type' => 'language_configuration',
             '#entity_information' => [
diff --git a/core/modules/system/src/Form/ThemeAdminForm.php b/core/modules/system/src/Form/ThemeAdminForm.php
index e8d17ed..af605b0 100644
--- a/core/modules/system/src/Form/ThemeAdminForm.php
+++ b/core/modules/system/src/Form/ThemeAdminForm.php
@@ -27,7 +27,7 @@ protected function getEditableConfigNames() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, FormStateInterface $form_state, array $theme_options = NULL) {
+  public function buildForm(array $form, FormStateInterface $form_state, array $theme_options = []) {
     // Administration theme settings.
     $form['admin_theme'] = [
       '#type' => 'details',
diff --git a/core/modules/update/src/Form/UpdateManagerUpdate.php b/core/modules/update/src/Form/UpdateManagerUpdate.php
index 0b31968..272b4f4 100644
--- a/core/modules/update/src/Form/UpdateManagerUpdate.php
+++ b/core/modules/update/src/Form/UpdateManagerUpdate.php
@@ -64,13 +64,10 @@ public static function create(ContainerInterface $container) {
   public function buildForm(array $form, FormStateInterface $form_state) {
     $this->moduleHandler->loadInclude('update', 'inc', 'update.manager');
 
-    $last_markup = [
+    $form['last_check'] = [
       '#theme' => 'update_last_check',
       '#last' => $this->state->get('update.last_check') ?: 0,
     ];
-    $form['last_check'] = [
-      '#markup' => \Drupal::service('renderer')->render($last_markup),
-    ];
 
     if (!_update_manager_check_backends($form, 'update')) {
       return $form;
diff --git a/core/modules/user/src/AccountForm.php b/core/modules/user/src/AccountForm.php
index d695968..4899d0b 100644
--- a/core/modules/user/src/AccountForm.php
+++ b/core/modules/user/src/AccountForm.php
@@ -111,6 +111,8 @@ public function form(array $form, FormStateInterface $form_state) {
     if (!$register) {
       $form['account']['pass'] = [
         '#type' => 'password_confirm',
+        '#title' => $this->t('Password'),
+        '#title_display' => 'invisible',
         '#size' => 25,
         '#description' => $this->t('To change the current user password, enter the new password in both fields.'),
       ];
@@ -153,6 +155,8 @@ public function form(array $form, FormStateInterface $form_state) {
     elseif (!$config->get('verify_mail') || $admin) {
       $form['account']['pass'] = [
         '#type' => 'password_confirm',
+        '#title' => $this->t('Password'),
+        '#title_display' => 'invisible',
         '#size' => 25,
         '#description' => $this->t('Provide a password for the new account in both fields.'),
         '#required' => TRUE,
diff --git a/core/modules/views/src/Form/ViewsForm.php b/core/modules/views/src/Form/ViewsForm.php
index 575b923..bf3f128 100644
--- a/core/modules/views/src/Form/ViewsForm.php
+++ b/core/modules/views/src/Form/ViewsForm.php
@@ -95,7 +95,7 @@ public function __construct(ClassResolverInterface $class_resolver, UrlGenerator
   /**
    * {@inheritdoc}
    */
-  public static function create(ContainerInterface $container, $view_id = NULL, $view_display_id = NULL, array $view_args = NULL) {
+  public static function create(ContainerInterface $container, $view_id = NULL, $view_display_id = NULL, array $view_args = []) {
     return new static(
       $container->get('class_resolver'),
       $container->get('url_generator'),
diff --git a/core/modules/workflows/src/Entity/Workflow.php b/core/modules/workflows/src/Entity/Workflow.php
index 2450fb7..672c271 100644
--- a/core/modules/workflows/src/Entity/Workflow.php
+++ b/core/modules/workflows/src/Entity/Workflow.php
@@ -25,10 +25,8 @@
  *       "delete" = "Drupal\workflows\Form\WorkflowDeleteForm",
  *       "add-state" = "Drupal\workflows\Form\WorkflowStateAddForm",
  *       "edit-state" = "Drupal\workflows\Form\WorkflowStateEditForm",
- *       "delete-state" = "Drupal\workflows\Form\WorkflowStateDeleteForm",
  *       "add-transition" = "Drupal\workflows\Form\WorkflowTransitionAddForm",
  *       "edit-transition" = "Drupal\workflows\Form\WorkflowTransitionEditForm",
- *       "delete-transition" = "Drupal\workflows\Form\WorkflowTransitionDeleteForm",
  *     },
  *     "route_provider" = {
  *       "html" = "Drupal\Core\Entity\Routing\AdminHtmlRouteProvider",
diff --git a/core/tests/Drupal/KernelTests/Core/Form/FormElementTitleTest.php b/core/tests/Drupal/KernelTests/Core/Form/FormElementTitleTest.php
new file mode 100644
index 0000000..2137823
--- /dev/null
+++ b/core/tests/Drupal/KernelTests/Core/Form/FormElementTitleTest.php
@@ -0,0 +1,685 @@
+<?php
+
+namespace Drupal\KernelTests\Core\Form;
+
+use Drupal\comment\CommentInterface;
+use Drupal\Component\Utility\ArgumentsResolver;
+use Drupal\Component\Utility\Crypt;
+use Drupal\Core\Config\Entity\ConfigEntityInterface;
+use Drupal\Core\DependencyInjection\ContainerBuilder;
+use Drupal\Core\DependencyInjection\ServiceModifierInterface;
+use Drupal\Core\Entity\ContentEntityStorageInterface;
+use Drupal\Core\Entity\EntityFormInterface;
+use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Entity\EntityListBuilderInterface;
+use Drupal\Core\Entity\EntityTypeInterface;
+use Drupal\Core\Extension\ExtensionDiscovery;
+use Drupal\Core\Form\FormInterface;
+use Drupal\Core\Form\FormState;
+use Drupal\Core\Language\Language;
+use Drupal\Core\Render\Element;
+use Drupal\Core\Routing\NullRouteMatch;
+use Drupal\Core\Routing\RouteMatch;
+use Drupal\KernelTests\KernelTestBase;
+use Drupal\language\Entity\ConfigurableLanguage;
+use Drupal\media\Entity\MediaType;
+use Drupal\Tests\Core\Menu\MenuLinkMock;
+use Drupal\update\UpdateProcessorInterface;
+use Drupal\user\Entity\User;
+use Drupal\views\ViewEntityInterface;
+use Drupal\views_ui\Form\Ajax\ViewsFormInterface;
+use Drupal\views_ui\ViewUI;
+use Drupal\workflows\Entity\Workflow;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\Routing\Route;
+
+/**
+ * Ensures all form elements have a #title defined.
+ *
+ * @group Form
+ */
+class FormElementTitleTest extends KernelTestBase implements ServiceModifierInterface {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $modules = ['system', 'user', 'ckeditor'];
+
+  /**
+   * @todo.
+   *
+   * @var mixed[][]
+   */
+  protected $scalars = [];
+
+  /**
+   * @todo.
+   *
+   * @var object[][]
+   */
+  protected $objects = [];
+
+  /**
+   * @todo.
+   *
+   * @var mixed[][]
+   */
+  protected $formStateAdditions = [];
+
+  /**
+   * The render element types to ignore.
+   *
+   * These elements do not receive input, but are marked with #input => TRUE.
+   *
+   * @var string[]
+   */
+  protected $typesToSkip = [
+    'field_ui_table',
+    'table',
+    'tableselect',
+  ];
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+
+    // Install the system and user modules.
+    $this->installSchema('system', ['key_value_expire', 'sequences']);
+    $this->installConfig(['system']);
+    $this->installEntitySchema('user');
+    $this->installSchema('user', ['users_data']);
+
+    // Set up a theme.
+    $this->container->get('theme_installer')->install(['stark']);
+
+    // Set up a current user.
+    $user = User::create(['name' => 'Clu']);
+    $user->save();
+    $this->container->get('current_user')->setAccount($user);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function alter(ContainerBuilder $container) {
+    // Spoof the update processor to prevent it from dialing out.
+    $update_processor = $this->prophesize(UpdateProcessorInterface::class);
+    $container->set('update.processor', $update_processor->reveal());
+  }
+
+  /**
+   * Performs accessibility tests on all forms provided by modules.
+   */
+  public function testFormAccessibility() {
+    // Find all forms in all modules, installing all modules that provide forms.
+    $forms = $this->findForms();
+
+    // Create an entity of each type needed by forms.
+    $entities = $this->createEntities();
+    // Prepare the additional parameters for special form classes.
+    $this->prepareForms($entities);
+
+    // Loop over each entity
+    foreach ($entities as $entity) {
+      $this->checkEntityListForm($entity, $entities);
+
+      $entity_handlers = $entity->getEntityType()->getHandlerClasses();
+      if (!empty($entity_handlers['form'])) {
+        $this->checkForms($entity_handlers['form'], $entities, $entity->getEntityTypeId());
+      }
+    }
+
+    $this->checkForms($forms, $entities, NULL);
+  }
+
+  /**
+   * Finds all defined forms.
+   *
+   * Also installs every module that provides forms.
+   *
+   * @return string[]
+   *   An array of fully qualified class names of forms.
+   */
+  protected function findForms() {
+    // Scan all modules for forms.
+    $forms = [];
+    $discovery = new ExtensionDiscovery($this->root);
+    $modules = $discovery->scan('module', FALSE);
+    $modules_to_install = [];
+    foreach ($modules as $module) {
+      $module_name = $module->getName();
+      $directory = $module->getPath() . '/src';
+      if (is_dir($directory)) {
+        $iterator = new \RecursiveIteratorIterator(
+          new \RecursiveDirectoryIterator($directory, \RecursiveDirectoryIterator::SKIP_DOTS)
+        );
+        foreach ($iterator as $file_info) {
+          if ($file_info->getExtension() == 'php') {
+            $sub_path = $iterator->getSubIterator()->getSubPath();
+            $sub_path = $sub_path ? str_replace(DIRECTORY_SEPARATOR, '\\', $sub_path) . '\\' : '';
+            $class = "Drupal\\$module_name\\$sub_path" . $file_info->getBasename('.php');
+            if (is_subclass_of($class, FormInterface::class)) {
+              $forms[] = $class;
+              $modules_to_install[$module_name] = $module_name;
+            }
+          }
+        }
+      }
+    }
+
+    // @todo.
+    $this->container->get('module_installer')->install($modules_to_install);
+
+    $forms = array_filter($forms, function ($class) {
+      // Don't attempt to instantiate abstract forms.
+      if ((new \ReflectionClass($class))->isAbstract()) {
+        return FALSE;
+      }
+
+      // @todo.
+      if (is_subclass_of($class, EntityFormInterface::class)) {
+        return FALSE;
+      }
+
+      // @todo.
+      if (is_subclass_of($class, EntityListBuilderInterface::class)) {
+        return FALSE;
+      }
+
+      return TRUE;
+    });
+
+    return $forms;
+  }
+
+  /**
+   * Creates an entity for each entity type.
+   *
+   * @return \Drupal\Core\Entity\EntityInterface[]
+   *   An array of entities.
+   */
+  protected function createEntities() {
+    $entity_values = [];
+    $entity_values['action'] = [
+      'plugin' => 'user_block_user_action',
+    ];
+    $entity_values['block'] = [
+      'plugin' => 'page_title_block',
+    ];
+    $entity_values['comment'] = [
+      'field_name' => 'comment',
+      'entity_type' => 'user',
+      'entity_id' => 1,
+      'uid' => 1,
+      'pid' => 0,
+      'status' => CommentInterface::PUBLISHED,
+    ];
+    $entity_values['comment_type'] = [
+      'id' => 'comment',
+      'target_entity_type_id' => 'user',
+    ];
+    $entity_values['editor'] = [
+      'format' => 'my_filter_format',
+      'editor' => 'ckeditor',
+      'image_upload' => [
+        'status' => FALSE,
+        'scheme' => file_default_scheme(),
+        'directory' => 'inline-images',
+        'max_size' => '',
+        'max_dimensions' => [
+          'width' => '',
+          'height' => '',
+        ],
+      ],
+    ];
+    $entity_values['entity_form_display'] = [
+      'targetEntityType' => 'user',
+      'bundle' => 'user',
+      'mode' => 'default',
+      'status' => TRUE,
+      'content' => [
+        'comment' => [
+          'type' => 'comment_default',
+          'region' => 'content',
+          'weight' => 0,
+          'settings' => [],
+          'third_party_settings' => [],
+        ],
+      ],
+    ];
+    $entity_values['entity_view_mode'] = [
+      'id' => 'user.default',
+      'targetEntityType' => 'user',
+    ];
+    $entity_values['entity_form_mode'] = [
+      'id' => 'user.default',
+      'targetEntityType' => 'user',
+    ];
+    $entity_values['entity_view_display'] = [
+      'targetEntityType' => 'user',
+      'bundle' => 'user',
+      'mode' => 'default',
+    ];
+    $entity_values['field_config'] = [
+      'field_name' => 'comment',
+      'entity_type' => 'user',
+      'bundle' => 'user',
+    ];
+    $entity_values['field_storage_config'] = [
+      'field_name' => 'comment',
+      'type' => 'comment',
+      'entity_type' => 'user',
+      'settings' => ['comment_type' => 'comment'],
+    ];
+    $entity_values['filter_format'] = [
+      'format' => 'my_filter_format',
+    ];
+    $entity_values['image_style'] = [
+      'effects' => [
+        'some-uuid' => [
+          'uuid' => 'some-uuid',
+          'id' => 'image_scale',
+          'weight' => 0,
+          'data' => [
+            'width' => 420,
+            'height' => 420,
+            'upscale' => FALSE,
+          ],
+        ],
+      ],
+    ];
+    $entity_values['media'] = [
+      'bundle' => 'file',
+    ];
+    $entity_values['menu'] = [
+      'id' => 'mock',
+    ];
+    $entity_values['menu_link_content'] = [
+      'menu_name' => 'mock',
+    ];
+    $entity_values['node'] = [
+      'uid' => 1,
+      'status' => TRUE,
+      'published' => TRUE,
+      'type' => 'my_book',
+      'title' => 'My book',
+      'book' => [
+        'bid' => 'new',
+      ],
+    ];
+    $entity_values['node_type'] = [
+      'type' => 'my_book',
+    ];
+    $entity_values['search_page'] = [
+      'plugin' => 'user_search',
+    ];
+
+    // Load existing entities for use by forms.
+    $entities = [];
+    $entities['configurable_language'] = ConfigurableLanguage::load('en');
+    $entities['media_type'] = MediaType::load('file');
+    $entities['workflow'] = Workflow::load('editorial');
+
+    $entity_type_manager = $this->container->get('entity_type.manager');
+
+    /** @var \Drupal\Core\Entity\EntityTypeInterface[] $entity_types */
+    $entity_types = $entity_type_manager->getDefinitions();
+    // Adjust entity types to account for necessary order of installation.
+    $entity_types = [
+      'field_storage_config' => $entity_types['field_storage_config'],
+      'field_config' => $entity_types['field_config'],
+      'entity_form_mode' => $entity_types['entity_form_mode'],
+      'entity_form_display' => $entity_types['entity_form_display'],
+      'filter_format' => $entity_types['filter_format'],
+      'editor' => $entity_types['editor'],
+    ] + array_filter($entity_types, function (EntityTypeInterface $entity_type) {
+      return $entity_type->entityClassImplements(ConfigEntityInterface::class);
+    }) + [
+      'node' => $entity_types['node'],
+    ] + $entity_types;
+
+    foreach ($entity_types as $entity_type_id => $entity_type) {
+      if ((!empty($entity_type->getHandlerClasses()['form']) || isset($entity_values[$entity_type_id])) && !isset($entities[$entity_type_id])) {
+        if (!isset($entity_values[$entity_type_id])) {
+          $entity_values[$entity_type_id] = [];
+        }
+
+        $entity_storage = $entity_type_manager->getStorage($entity_type_id);
+        if ($entity_storage instanceof ContentEntityStorageInterface) {
+          $bundle_entity_type_id = $entity_type->getBundleEntityType();
+          $bundle = $bundle_entity_type_id ? $entities[$bundle_entity_type_id]->id() : FALSE;
+          $entity = $entity_storage->createWithSampleValues($bundle, $entity_values[$entity_type_id], TRUE);
+        }
+        else {
+          $values = $entity_values[$entity_type_id];
+          $values += [$entity_type->getKey('id') => "id__$entity_type_id"];
+          if ($entity_type->hasKey('published')) {
+            $values[$entity_type->getKey('published')] = TRUE;
+          }
+          $entity = $entity_storage->create($values);
+        }
+
+        $entity->save();
+
+        // @todo.
+        if ($entity_storage->hasData()) {
+          $entity_storage->resetCache([$entity->id()]);
+          $entity = $entity_storage->load($entity->id());
+        }
+
+        // @todo.
+        if ($entity instanceof ViewEntityInterface) {
+          $entity = new ViewUI($entity);
+        }
+
+        $entities[$entity_type_id] = $entity;
+      }
+    }
+    return $entities;
+  }
+
+  /**
+   * @todo.
+   */
+  protected function prepareForms(array $entities) {
+    // @todo.
+    $this->container->get('ban.ip_manager')->banIp('86.7.5.309');
+
+    // Needed for Drupal\system\Form\CronForm.
+    $this->container->get('state')->set('system.cron_key', Crypt::randomBytesBase64(55));
+
+    // Needed for \Drupal\update\Form\UpdateManagerInstall.
+    if (!defined('DRUPAL_TEST_IN_CHILD_SITE')) {
+      define('DRUPAL_TEST_IN_CHILD_SITE', FALSE);
+    }
+
+    // @todo.
+    $user = User::load(2);
+    $tempstore = $this->container->get('user.private_tempstore');
+    $tempstore->get('user_user_operations_cancel')->set(1, [$user]);
+    $tempstore->get('node_multiple_delete_confirm')->set(1, [
+      $entities['node']->id() => [
+        $entities['node']->language()->getId(),
+      ],
+    ]);
+    $tempstore->get('comment_multiple_delete_confirm')->set(1, [
+      $entities['comment']->id() => [
+        $entities['comment']->language()->getId(),
+      ],
+    ]);
+    $tempstore->get('media_multiple_delete_confirm')->set(1, [
+      $entities['media']->id() => [
+        $entities['media']->language()->getId(),
+      ],
+    ]);
+
+    // @todo.
+    $keyvalue_expirable = $this->container->get('keyvalue.expirable');
+    $keyvalue_expirable->get('modules_uninstall')->set(1, ['telephone']);
+    $keyvalue_expirable->get('module_list')->set(1, [
+      'install' => [
+        'telephone' => 'Telephone',
+      ],
+      'experimental' => [],
+      'dependencies' => [],
+    ]);
+
+    // @todo
+    $this->objects['Drupal\content_translation\Form\ContentTranslationDeleteForm']['language'] = new Language(['id' => 'en']);
+
+    // @todo.
+    $route_match = new RouteMatch('the_route_name', new Route('/the/{node_type}/path'), ['node_type' => $entities['node_type']]);
+    $classes = [
+      'Drupal\config_translation\Form\ConfigTranslationAddForm',
+      'Drupal\config_translation\Form\ConfigTranslationEditForm',
+      'Drupal\config_translation\Form\ConfigTranslationDeleteForm',
+    ];
+    foreach ($classes as $class) {
+      $this->objects[$class]['route_match'] = $route_match;
+      $this->scalars[$class]['plugin_id'] = 'node_type';
+      $this->scalars[$class]['langcode'] = 'en';
+    }
+
+    // @todo.
+    $executable_view = $entities['view']->getExecutable();
+    $executable_view->initHandlers();
+    $this->objects['Drupal\views\Form\ViewsForm']['view'] = $executable_view;
+    $this->objects['Drupal\views\Form\ViewsFormMainForm']['view'] = $executable_view;
+    $this->formStateAdditions['Drupal\views\Form\ViewsExposedForm']['view'] = $executable_view;
+
+    // @todo.
+    $this->scalars['Drupal\views_ui\ViewAddForm']['display_id'] = 'default';
+    $this->scalars['Drupal\views_ui\ViewDuplicateForm']['display_id'] = 'default';
+    $this->scalars['Drupal\views_ui\ViewEditForm']['display_id'] = 'default';
+    $this->scalars['Drupal\views_ui\ViewPreviewForm']['display_id'] = 'default';
+
+    // @todo
+    $this->formStateAdditions['Drupal\views_ui\Form\Ajax\AddHandler']['type'] = 'sort';
+    $this->formStateAdditions['Drupal\views_ui\Form\Ajax\ConfigHandler']['type'] = 'sort';
+    $this->formStateAdditions['Drupal\views_ui\Form\Ajax\ConfigHandlerExtra']['type'] = 'sort';
+    $this->formStateAdditions['Drupal\views_ui\Form\Ajax\ConfigHandlerGroup']['type'] = 'sort';
+    $this->formStateAdditions['Drupal\views_ui\Form\Ajax\Rearrange']['type'] = 'sort';
+
+    // @todo.
+    $this->objects['Drupal\quickedit\Form\QuickEditFieldForm']['entity'] = $entities['user'];
+    $this->scalars['Drupal\quickedit\Form\QuickEditFieldForm']['field_name'] = 'comment';
+
+    // @todo.
+    $menu_link_plugin = MenuLinkMock::create(['id' => 'test']);
+    $this->objects['Drupal\menu_ui\Form\MenuLinkEditForm']['menu_link_plugin'] = $menu_link_plugin;
+    $this->objects['Drupal\menu_ui\Form\MenuLinkResetForm']['menu_link_plugin'] = $menu_link_plugin;
+
+    // @todo.
+    $this->objects['Drupal\content_moderation\Form\EntityModerationForm']['entity'] = $entities['node'];
+
+    // @todo.
+    $this->scalars['Drupal\content_moderation\Form\ContentModerationConfigureEntityTypesForm']['entity_type_id'] = 'node';
+
+    // @todo.
+    $this->scalars['Drupal\user\Form\UserPasswordResetForm'] = [
+      'expiration_date' => 'Sun, 11/19/1978 - 05:00',
+      'timestamp' => 280299600,
+      'hash' => user_pass_rehash($entities['user'], $this->container->get('datetime.time')->getRequestTime()),
+    ];
+
+    // @todo.
+    $this->scalars['Drupal\image\Form\ImageEffectAddForm']['image_effect'] = 'image_crop';
+    $this->scalars['Drupal\image\Form\ImageEffectDeleteForm']['image_effect'] = 'some-uuid';
+    $this->scalars['Drupal\image\Form\ImageEffectEditForm']['image_effect'] = 'some-uuid';
+
+    // @todo.
+    $this->scalars['Drupal\workflows\Form\WorkflowStateEditForm']['workflow_state'] = 'published';
+    $this->scalars['Drupal\workflows\Form\WorkflowStateDeleteForm']['workflow_state'] = 'published';
+    $this->scalars['Drupal\workflows\Form\WorkflowTransitionEditForm']['workflow_transition'] = 'publish';
+    $this->scalars['Drupal\workflows\Form\WorkflowTransitionDeleteForm']['workflow_transition'] = 'publish';
+
+    // @todo.
+    $this->scalars['Drupal\search\Form\SearchPageAddForm']['search_plugin_id'] = 'user_search';
+
+    // @todo.
+    $this->scalars['Drupal\ban\Form\BanDelete']['ban_id'] = 1;
+
+    // @todo.
+    $this->scalars['Drupal\system\Form\PrepareModulesEntityUninstallForm']['entity_type_id'] = 'node';
+
+    // @todo.
+    $this->scalars['Drupal\field_ui\Form\EntityDisplayModeAddForm']['entity_type_id'] = 'node';
+    $this->scalars['Drupal\field_ui\Form\EntityFormModeAddForm']['entity_type_id'] = 'node';
+
+    // @todo.
+    $this->scalars['Drupal\block\BlockListBuilder']['theme'] = 'stark';
+
+    // @todo.
+    $this->scalars['Drupal\field_ui\Form\FieldStorageAddForm']['entity_type_id'] = 'user';
+    $this->scalars['Drupal\field_ui\Form\FieldStorageAddForm']['bundle'] = 'user';
+
+    // @todo.
+    $this->scalars['Drupal\field_ui\Form\FieldStorageConfigEditForm']['field_config'] = 'user.user.comment';
+  }
+
+  /**
+   * Checks each entity list form.
+   *
+   * @param \Drupal\Core\Entity\EntityInterface $entity
+   *   The entity.
+   * @param \Drupal\Core\Entity\EntityInterface[] $entities
+   *   An array of entities.
+   */
+  protected function checkEntityListForm(EntityInterface $entity, array $entities) {
+    $entity_type_manager = $this->container->get('entity_type.manager');
+
+    $entity_type = $entity->getEntityType();
+    $entity_type_id = $entity->getEntityTypeId();
+
+    $class = $entity_type->getListBuilderClass();
+    if (is_subclass_of($class, FormInterface::class)) {
+      $list_builder = $entity_type_manager->getListBuilder($entity_type_id);
+
+      $arguments = $this->prepareArguments($entities, $list_builder, 'render');
+
+      $form = call_user_func_array([$list_builder, 'render'], $arguments);
+      $this->ensureFormElementTitle($form, $class);
+    }
+  }
+
+  /**
+   */
+  protected function prepareArguments(array $entities, $class, $method, $params_to_ignore = 0) {
+    if (is_object($class)) {
+      $object = $class;
+      $class = get_class($object);
+    }
+    else {
+      $object = $this->container->get('class_resolver')->getInstanceFromDefinition($class);
+    }
+
+    $reflection_method = new \ReflectionMethod($object, $method);
+    $number_of_parameters = $reflection_method->getNumberOfParameters();
+    // @todo.
+    if ($number_of_parameters == $params_to_ignore) {
+      return [];
+    }
+
+    // @todo.
+    $scalars = ['form' => []];
+    if (!empty($this->scalars[$class])) {
+      $scalars += $this->scalars[$class];
+    }
+    $objects = [];
+    if (!empty($this->objects[$class])) {
+      $objects += $this->objects[$class];
+    }
+    $objects += [
+      'form_state' => new FormState(),
+      'route_match' => new NullRouteMatch(),
+      'request' => new Request(),
+    ] + $entities;
+    $resolver = new ArgumentsResolver($scalars, $objects, []);
+
+    $unfiltered_arguments = $resolver->getArguments([$object, $method]);
+    $filtered_arguments = array_filter($unfiltered_arguments, function ($argument) {
+      return !is_null($argument);
+    });
+
+    $arguments = array_slice($filtered_arguments, $params_to_ignore);
+    if ($filtered_arguments === $unfiltered_arguments) {
+      return $arguments;
+    }
+
+    // @todo.
+    $number_of_satisfied_parameters = count($filtered_arguments);
+    if ($number_of_parameters > $number_of_satisfied_parameters) {
+      $parameters = $reflection_method->getParameters();
+      // @todo.
+      for ($i = $number_of_satisfied_parameters; $i < $number_of_parameters; $i++) {
+        $parameter = $parameters[$i];
+        // @todo.
+        if ($parameter->getClass()) {
+          $name = $parameter->getClass()->getName();
+          try {
+            $found_entity_type_id = $this->container->get('entity_type.repository')->getEntityTypeFromClass($name);
+          }
+          catch (\Exception $e) {
+            $found_entity_type_id = FALSE;
+          }
+          if ($found_entity_type_id && isset($entities[$found_entity_type_id])) {
+            $arguments[] = $entities[$found_entity_type_id];
+          }
+          else {
+            throw new \Exception(sprintf('Missing parameter %s %s for class %s', $name, $parameter->getName(), $class));
+          }
+        }
+        else {
+          $this->verbose(sprintf('Skipped optional parameter %s for class %s', $parameter->getName(), $class));
+        }
+      }
+    }
+    return $arguments;
+  }
+
+  /**
+   * Checks each form.
+   *
+   * @param string[] $form_classes
+   *   An array of fully qualified class names of forms.
+   * @param \Drupal\Core\Entity\EntityInterface[] $entities
+   *   An array of entities.
+   * @param string|null $entity_type_id
+   *   The entity type ID, if it exists.
+   */
+  protected function checkForms(array $form_classes, array $entities, $entity_type_id) {
+    $entity_form_builder = $this->container->get('entity.form_builder');
+    $form_builder = $this->container->get('form_builder');
+
+    // Perform tests on all forms.
+    foreach ($form_classes as $operation => $class) {
+      $form_state = new FormState();
+      $form_state->addBuildInfo('args', $this->prepareArguments($entities, $class, 'buildForm', 2));
+
+      if (is_subclass_of($class, ViewsFormInterface::class)) {
+        $form_state->set('view', $entities['view']);
+        $form_state->set('display_id', 'default');
+        $form_state->loadInclude('views_ui', 'inc', 'admin');
+      }
+
+      if (isset($this->formStateAdditions[$class])) {
+        foreach ($this->formStateAdditions[$class] as $key => $value) {
+          $form_state->set($key, $value);
+        }
+      }
+
+      if (is_subclass_of($class, EntityFormInterface::class)) {
+        $form = $entity_form_builder->getForm($entities[$entity_type_id], $operation, $form_state->getCacheableArray());
+      }
+      else {
+        $form = $form_builder->buildForm($class, $form_state);
+      }
+
+      $this->ensureFormElementTitle($form, $class);
+    }
+  }
+
+  /**
+   * Tests that all form elements of a form have a title.
+   *
+   * @param array $element
+   *   An associative array containing a form element.
+   * @param string $class
+   *   The class name used to build the form.
+   */
+  protected function ensureFormElementTitle(array $element, $class) {
+    foreach (Element::children($element) as $key) {
+      $this->ensureFormElementTitle($element[$key], $class);
+
+      // Skip any element without a valid #type or that does not accept input.
+      if (!isset($element['#type']) || in_array($element['#type'], $this->typesToSkip) || empty($element['#input'])) {
+        continue;
+      }
+
+      $this->assertArrayHasKey('#title', $element, sprintf('%s: %s (%s)', $class, implode('][', $element['#parents']), $element['#type']));
+    }
+  }
+
+}
