diff --git a/core/lib/Drupal/Core/Entity/ContentEntityBase.php b/core/lib/Drupal/Core/Entity/ContentEntityBase.php
index 5376644c54..f566e8bdc3 100644
--- a/core/lib/Drupal/Core/Entity/ContentEntityBase.php
+++ b/core/lib/Drupal/Core/Entity/ContentEntityBase.php
@@ -1267,22 +1267,26 @@ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
       $fields[$entity_type->getKey('id')] = BaseFieldDefinition::create('integer')
         ->setLabel(new TranslatableMarkup('ID'))
         ->setReadOnly(TRUE)
+        ->setStorageRequired(TRUE)
         ->setSetting('unsigned', TRUE);
     }
     if ($entity_type->hasKey('uuid')) {
       $fields[$entity_type->getKey('uuid')] = BaseFieldDefinition::create('uuid')
         ->setLabel(new TranslatableMarkup('UUID'))
-        ->setReadOnly(TRUE);
+        ->setReadOnly(TRUE)
+        ->setStorageRequired(TRUE);
     }
     if ($entity_type->hasKey('revision')) {
       $fields[$entity_type->getKey('revision')] = BaseFieldDefinition::create('integer')
         ->setLabel(new TranslatableMarkup('Revision ID'))
         ->setReadOnly(TRUE)
+        ->setStorageRequired(TRUE)
         ->setSetting('unsigned', TRUE);
     }
     if ($entity_type->hasKey('langcode')) {
       $fields[$entity_type->getKey('langcode')] = BaseFieldDefinition::create('language')
         ->setLabel(new TranslatableMarkup('Language'))
+        ->setStorageRequired(TRUE)
         ->setDisplayOptions('view', [
           'region' => 'hidden',
         ])
diff --git a/core/lib/Drupal/Core/Entity/EntityFieldManager.php b/core/lib/Drupal/Core/Entity/EntityFieldManager.php
index 63c35e9743..57bbef2fb7 100644
--- a/core/lib/Drupal/Core/Entity/EntityFieldManager.php
+++ b/core/lib/Drupal/Core/Entity/EntityFieldManager.php
@@ -216,7 +216,8 @@ protected function buildBaseFieldDefinitions($entity_type_id) {
           ->setDescription($this->t('A flag indicating whether this is the default translation.'))
           ->setTranslatable(TRUE)
           ->setRevisionable(TRUE)
-          ->setDefaultValue(TRUE);
+          ->setDefaultValue(TRUE)
+          ->setStorageRequired(TRUE);
       }
     }
 
diff --git a/core/lib/Drupal/Core/Entity/EntityPublishedTrait.php b/core/lib/Drupal/Core/Entity/EntityPublishedTrait.php
index eb4d82e89b..8db501b980 100644
--- a/core/lib/Drupal/Core/Entity/EntityPublishedTrait.php
+++ b/core/lib/Drupal/Core/Entity/EntityPublishedTrait.php
@@ -37,6 +37,12 @@ public static function publishedBaseFieldDefinitions(EntityTypeInterface $entity
         ->setLabel(new TranslatableMarkup('Published'))
         ->setRevisionable(TRUE)
         ->setTranslatable(TRUE)
+        // The published field cannot be made required, as that makes it
+        // impossible to create unpublished entities using the user interface in
+        // case the checkbox widget is used.
+        // @todo Change this to setRequired() once
+        //   https://www.drupal.org/project/drupal/issues/2619328 is fixed.
+        ->setStorageRequired(TRUE)
         ->setDefaultValue(TRUE),
     ];
   }
diff --git a/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchema.php b/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchema.php
index 5b659a048d..1a59764e98 100644
--- a/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchema.php
+++ b/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchema.php
@@ -1200,7 +1200,6 @@ protected function addTableDefaults(&$schema) {
    *   A partial schema array for the base table.
    */
   protected function processBaseTable(ContentEntityTypeInterface $entity_type, array &$schema) {
-    $this->processIdentifierSchema($schema, $entity_type->getKey('id'));
   }
 
   /**
@@ -1215,7 +1214,6 @@ protected function processBaseTable(ContentEntityTypeInterface $entity_type, arr
    *   A partial schema array for the base table.
    */
   protected function processRevisionTable(ContentEntityTypeInterface $entity_type, array &$schema) {
-    $this->processIdentifierSchema($schema, $entity_type->getKey('revision'));
   }
 
   /**
@@ -1230,9 +1228,6 @@ protected function processRevisionTable(ContentEntityTypeInterface $entity_type,
    *   A partial schema array for the base table.
    */
   protected function processDataTable(ContentEntityTypeInterface $entity_type, array &$schema) {
-    // Marking the respective fields as NOT NULL makes the indexes more
-    // performant.
-    $schema['fields'][$entity_type->getKey('default_langcode')]['not null'] = TRUE;
   }
 
   /**
@@ -1247,9 +1242,6 @@ protected function processDataTable(ContentEntityTypeInterface $entity_type, arr
    *   A partial schema array for the base table.
    */
   protected function processRevisionDataTable(ContentEntityTypeInterface $entity_type, array &$schema) {
-    // Marking the respective fields as NOT NULL makes the indexes more
-    // performant.
-    $schema['fields'][$entity_type->getKey('default_langcode')]['not null'] = TRUE;
   }
 
   /**
@@ -1353,25 +1345,52 @@ protected function createSharedTableSchema(FieldStorageDefinitionInterface $stor
         if ($field_name == $created_field_name) {
           // Create field columns.
           $schema[$table_name] = $this->getSharedTableFieldSchema($storage_definition, $table_name, $column_names);
+
           if (!$only_save) {
+            $entity_schema = $this->getEntitySchema($this->entityType);
             foreach ($schema[$table_name]['fields'] as $name => $specifier) {
+              // Check if the field is part of the primary keys and pass along
+              // this information when adding the field.
+              // @see \Drupal\Core\Database\Schema::addField()
+              $new_keys = [];
+              if (isset($entity_schema[$table_name]['primary key']) && array_intersect($column_names, $entity_schema[$table_name]['primary key'])) {
+                $new_keys = ['primary key' => $entity_schema[$table_name]['primary key']];
+              }
+
               // Check if the field exists because it might already have been
               // created as part of the earlier entity type update event.
               if (!$schema_handler->fieldExists($table_name, $name)) {
-                $schema_handler->addField($table_name, $name, $specifier);
+                $schema_handler->addField($table_name, $name, $specifier, $new_keys);
               }
             }
-            if (!empty($schema[$table_name]['indexes'])) {
-              foreach ($schema[$table_name]['indexes'] as $name => $specifier) {
-                // Check if the index exists because it might already have been
-                // created as part of the earlier entity type update event.
-                $this->addIndex($table_name, $name, $specifier, $schema[$table_name]);
+
+            // Even if the field does not declare any indexes or unique keys
+            // itself, the field may be part of a key declared on the
+            // table-level.
+            $key_filter = function ($specifier) use ($column_names) {
+              foreach ($specifier as $key_column) {
+                $column_name = is_array($key_column) ? $key_column[0] : $key_column;
+                if (in_array($column_name, $column_names, TRUE)) {
+                  return TRUE;
+                }
               }
+              return FALSE;
+            };
+
+            $indexes = isset($schema[$table_name]['indexes']) ? $schema[$table_name]['indexes'] : [];
+            $indexes += array_filter($entity_schema[$table_name]['indexes'], $key_filter);
+            foreach ($indexes as $name => $specifier) {
+              // Check if the index exists because it might already have been
+              // created as part of the earlier entity type update event.
+              $this->addIndex($table_name, $name, $specifier, $entity_schema[$table_name]);
             }
-            if (!empty($schema[$table_name]['unique keys'])) {
-              foreach ($schema[$table_name]['unique keys'] as $name => $specifier) {
-                $schema_handler->addUniqueKey($table_name, $name, $specifier);
-              }
+
+            $unique_keys = isset($schema[$table_name]['unique keys']) ? $schema[$table_name]['unique keys'] : [];
+            $unique_keys += array_filter($entity_schema[$table_name]['unique keys'], $key_filter);
+            foreach ($unique_keys as $name => $specifier) {
+              // Check if the unique key exists because it might already have
+              // been created as part of the earlier entity type update event.
+              $this->addUniqueKey($table_name, $name, $specifier);
             }
           }
           // After creating the field schema skip to the next table.
@@ -1435,7 +1454,20 @@ protected function deleteSharedTableSchema(FieldStorageDefinitionInterface $stor
         if ($field_name == $deleted_field_name) {
           $schema = $this->getSharedTableFieldSchema($storage_definition, $table_name, $column_names);
 
-          // Drop indexes and unique keys first.
+          // Drop the primary key, indexes and unique keys first.
+          $entity_schema = $this->getEntitySchema($this->entityType);
+          if (array_intersect($column_names, $entity_schema[$table_name]['primary key'])) {
+            // Dropping a primary key must not leave a serial key, so we need to
+            // change any serial field to integer first.
+            foreach ($entity_schema[$table_name]['primary key'] as $column_name) {
+              if ($entity_schema[$table_name]['fields'][$column_name]['type'] === 'serial') {
+                $field_schema = $entity_schema[$table_name]['fields'][$column_name];
+                $field_schema['type'] = 'int';
+                $schema_handler->changeField($table_name, $column_name, $column_name, $field_schema);
+              }
+            }
+            $schema_handler->dropPrimaryKey($table_name);
+          }
           if (!empty($schema['indexes'])) {
             foreach ($schema['indexes'] as $name => $specifier) {
               $schema_handler->dropIndex($table_name, $name);
@@ -1609,15 +1641,22 @@ protected function updateSharedTableSchema(FieldStorageDefinitionInterface $stor
 
             // Handle NOT NULL constraints.
             foreach ($schema[$table_name]['fields'] as $column_name => $specifier) {
-              $not_null = !empty($specifier['not null']);
-              $original_not_null = !empty($original_schema[$table_name]['fields'][$column_name]['not null']);
-              if ($not_null !== $original_not_null) {
-                if ($not_null && $this->hasNullFieldPropertyData($table_name, $column_name)) {
-                  throw new EntityStorageException("The $column_name column cannot have NOT NULL constraints as it holds NULL values.");
+              // In case a NOT NULL constraint is added to a field of an entity
+              // type in an update and that entity type is later made
+              // revisionable in a post-update, $schema will already contain
+              // data for the revision table, even though the revision table
+              // does not yet exist. Ignore this table in this case.
+              if (!empty($original_schema[$table_name]['fields'][$column_name])) {
+                $not_null = !empty($specifier['not null']);
+                $original_not_null = !empty($original_schema[$table_name]['fields'][$column_name]['not null']);
+                if ($not_null !== $original_not_null) {
+                  if ($not_null && $this->hasNullFieldPropertyData($table_name, $column_name)) {
+                    throw new EntityStorageException("The $column_name column cannot have NOT NULL constraints as it holds NULL values.");
+                  }
+                  $column_schema = $original_schema[$table_name]['fields'][$column_name];
+                  $column_schema['not null'] = $not_null;
+                  $schema_handler->changeField($table_name, $field_name, $field_name, $column_schema);
                 }
-                $column_schema = $original_schema[$table_name]['fields'][$column_name];
-                $column_schema['not null'] = $not_null;
-                $schema_handler->changeField($table_name, $field_name, $field_name, $column_schema);
               }
             }
 
@@ -1632,19 +1671,36 @@ protected function updateSharedTableSchema(FieldStorageDefinitionInterface $stor
                 $schema_handler->dropUniqueKey($table_name, $name);
               }
             }
-            // Create new indexes and unique keys.
-            if (!empty($schema[$table_name]['indexes'])) {
-              foreach ($schema[$table_name]['indexes'] as $name => $specifier) {
-                // Check if the index exists because it might already have been
-                // created as part of the earlier entity type update event.
-                $this->addIndex($table_name, $name, $specifier, $schema[$table_name]);
 
+            // Even if the field does not declare any indexes or unique keys
+            // itself, the field may be part of a key declared on the
+            // table-level.
+            $entity_schema = $this->getEntitySchema($this->entityType);
+            $key_filter = function ($specifier) use ($column_names) {
+              foreach ($specifier as $key_column) {
+                $column_name = is_array($key_column) ? $key_column[0] : $key_column;
+                if (in_array($column_name, $column_names, TRUE)) {
+                  return TRUE;
+                }
               }
+              return FALSE;
+            };
+
+            // Create new indexes and unique keys.
+            $indexes = isset($schema[$table_name]['indexes']) ? $schema[$table_name]['indexes'] : [];
+            $indexes += array_filter($entity_schema[$table_name]['indexes'], $key_filter);
+            foreach ($indexes as $name => $specifier) {
+              // Check if the index exists because it might already have been
+              // created as part of the earlier entity type update event.
+              $this->addIndex($table_name, $name, $specifier, $entity_schema[$table_name]);
             }
-            if (!empty($schema[$table_name]['unique keys'])) {
-              foreach ($schema[$table_name]['unique keys'] as $name => $specifier) {
-                $schema_handler->addUniqueKey($table_name, $name, $specifier);
-              }
+
+            $unique_keys = isset($schema[$table_name]['unique keys']) ? $schema[$table_name]['unique keys'] : [];
+            $unique_keys += array_filter($entity_schema[$table_name]['unique keys'], $key_filter);
+            foreach ($unique_keys as $name => $specifier) {
+              // Check if the unique key exists because it might already have
+              // been created as part of the earlier entity type update event.
+              $this->addUniqueKey($table_name, $name, $specifier);
             }
             // After deleting the field schema skip to the next table.
             break;
@@ -1811,7 +1867,7 @@ protected function getSharedTableFieldSchema(FieldStorageDefinitionInterface $st
     }
 
     $field_name = $storage_definition->getName();
-    $base_table = $this->storage->getBaseTable();
+    $properties = $storage_definition->getPropertyDefinitions();
 
     // Define the initial values, if any.
     $initial_value = $initial_value_from_field = [];
@@ -1850,28 +1906,23 @@ protected function getSharedTableFieldSchema(FieldStorageDefinitionInterface $st
     // A shared table contains rows for entities where the field is empty
     // (since other fields stored in the same table might not be empty), thus
     // the only columns that can be 'not null' are those for required
-    // properties of required fields. For now, we only hardcode 'not null' to a
-    // few "entity keys", in order to keep their indexes optimized.
-    // @todo Fix this in https://www.drupal.org/node/2841291.
-    $not_null_keys = $this->entityType->getKeys();
-    // Label and the 'revision_translation_affected' fields are not necessarily
-    // required.
-    unset($not_null_keys['label'], $not_null_keys['revision_translation_affected']);
+    // properties of required fields.
+    $field_storage_is_required = $storage_definition->isStorageRequired();
     // Because entity ID and revision ID are both serial fields in the base and
     // revision table respectively, the revision ID is not known yet, when
     // inserting data into the base table. Instead the revision ID in the base
     // table is updated after the data has been inserted into the revision
     // table. For this reason the revision ID field cannot be marked as NOT
     // NULL.
-    if ($table_name == $base_table) {
-      unset($not_null_keys['revision']);
+    if ($table_name === $this->storage->getBaseTable() && $field_name === $this->entityType->getKey('revision')) {
+      $field_storage_is_required = FALSE;
     }
 
     foreach ($column_mapping as $field_column_name => $schema_field_name) {
       $column_schema = $field_schema['columns'][$field_column_name];
 
       $schema['fields'][$schema_field_name] = $column_schema;
-      $schema['fields'][$schema_field_name]['not null'] = in_array($field_name, $not_null_keys);
+      $schema['fields'][$schema_field_name]['not null'] = $field_storage_is_required && $properties[$field_column_name]->isRequired();
 
       // Use the initial value of the field storage, if available.
       if ($initial_value && isset($initial_value[$field_column_name])) {
@@ -1894,6 +1945,15 @@ protected function getSharedTableFieldSchema(FieldStorageDefinitionInterface $st
       $schema['foreign keys'] = $this->getFieldForeignKeys($field_name, $field_schema, $column_mapping);
     }
 
+    // Process the 'id' and 'revision' entity keys for the base and revision
+    // tables.
+    if ($field_name === $this->entityType->getKey('id') && $table_name === $this->storage->getBaseTable()) {
+      $this->processIdentifierSchema($schema, $this->entityType->getKey('id'));
+    }
+    if ($field_name === $this->entityType->getKey('revision') && $table_name === $this->storage->getRevisionTable()) {
+      $this->processIdentifierSchema($schema, $this->entityType->getKey('revision'));
+    }
+
     return $schema;
   }
 
@@ -2221,6 +2281,16 @@ protected function hasColumnChanges(FieldStorageDefinitionInterface $storage_def
           $definition_spec = array_intersect_key($definition_schema[$table]['fields'][$name], $keys);
           $stored_spec = array_intersect_key($spec, $keys);
           if ($definition_spec != $stored_spec) {
+            // Prior to Drupal 8.5.0, the last installed schema for the 'id' and
+            // 'revision' fields of all content entity types was storing an
+            // 'int' type instead of 'serial', so we need to explicitly allow
+            // this conversion.
+            // @todo Remove this in 9.0.x.
+            // @see system_update_8501()
+            // @see https://www.drupal.org/node/2841291
+            if ($definition_spec['type'] === 'serial' && $stored_spec['type'] === 'int') {
+              return FALSE;
+            }
             return TRUE;
           }
         }
diff --git a/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchemaConverter.php b/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchemaConverter.php
index 60712eeb21..14c3aadc15 100644
--- a/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchemaConverter.php
+++ b/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchemaConverter.php
@@ -372,6 +372,7 @@ protected function updateFieldStorageDefinitionsToRevisionable(ContentEntityType
       ->setTargetEntityTypeId($entity_type->id())
       ->setTargetBundle(NULL)
       ->setLabel(new TranslatableMarkup('Revision ID'))
+      ->setStorageRequired(TRUE)
       ->setReadOnly(TRUE)
       ->setSetting('unsigned', TRUE);
 
diff --git a/core/modules/aggregator/aggregator.install b/core/modules/aggregator/aggregator.install
index 84e9614748..8c58497ebb 100644
--- a/core/modules/aggregator/aggregator.install
+++ b/core/modules/aggregator/aggregator.install
@@ -40,3 +40,13 @@ function aggregator_update_8200() {
   $field_definition->setRequired(TRUE);
   $definition_update_manager->updateFieldStorageDefinition($field_definition);
 }
+
+/**
+ * Add a default value for the 'Refresh' field for aggregator feed entities.
+ */
+function aggregator_update_8501() {
+  $definition_update_manager = \Drupal::entityDefinitionUpdateManager();
+  $field_definition = $definition_update_manager->getFieldStorageDefinition('refresh', 'aggregator_feed');
+  $field_definition->setDefaultValue(900);
+  $definition_update_manager->updateFieldStorageDefinition($field_definition);
+}
diff --git a/core/modules/aggregator/src/Entity/Feed.php b/core/modules/aggregator/src/Entity/Feed.php
index 3b14e8c24e..ad4049a970 100644
--- a/core/modules/aggregator/src/Entity/Feed.php
+++ b/core/modules/aggregator/src/Entity/Feed.php
@@ -168,6 +168,7 @@ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
     $fields['refresh'] = BaseFieldDefinition::create('list_integer')
       ->setLabel(t('Update interval'))
       ->setDescription(t('The length of time between feed updates. Requires a correctly configured cron maintenance task.'))
+      ->setDefaultValue(900)
       ->setSetting('unsigned', TRUE)
       ->setRequired(TRUE)
       ->setSetting('allowed_values', $period)
diff --git a/core/modules/block_content/block_content.install b/core/modules/block_content/block_content.install
index c6556e719c..6aecc64079 100644
--- a/core/modules/block_content/block_content.install
+++ b/core/modules/block_content/block_content.install
@@ -19,9 +19,14 @@ function block_content_update_dependencies() {
     $dependencies['block_content'][8400] = [
       'content_translation' => 8400,
     ];
-
-    return $dependencies;
   }
+  // The update function that adds the NOT NULL constraint to the status field
+  // must run after the status field has been created.
+  $dependencies['system'][8501] = [
+    'block_content' => 8400
+  ];
+
+  return $dependencies;
 }
 
 /**
diff --git a/core/modules/comment/comment.install b/core/modules/comment/comment.install
index c244fe4ce8..8dcf677c15 100644
--- a/core/modules/comment/comment.install
+++ b/core/modules/comment/comment.install
@@ -114,6 +114,17 @@ function comment_schema() {
 }
 
 /**
+ * Implements hook_update_dependencies().
+ */
+function comment_update_dependencies() {
+  // comment_update_8301() needs to run before system_update_8401().
+  $dependencies['system'][8401] = [
+    'comment' => 8301,
+  ];
+  return $dependencies;
+}
+
+/**
  * Clear caches to fix Comment entity list builder and operations Views field.
  */
 function comment_update_8001() {
diff --git a/core/modules/comment/tests/src/Kernel/CommentItemTest.php b/core/modules/comment/tests/src/Kernel/CommentItemTest.php
index 1a7fc655d5..85f6112561 100644
--- a/core/modules/comment/tests/src/Kernel/CommentItemTest.php
+++ b/core/modules/comment/tests/src/Kernel/CommentItemTest.php
@@ -71,6 +71,9 @@ public function testCommentItem() {
   public function testCommentAuthorName() {
     $this->installEntitySchema('comment');
 
+    $host = EntityTest::create(['name' => $this->randomString()]);
+    $host->save();
+
     // Create some comments.
     $comment = Comment::create([
       'subject' => 'My comment title',
@@ -78,6 +81,7 @@ public function testCommentAuthorName() {
       'name' => 'entity-test',
       'mail' => 'entity@localhost',
       'entity_type' => 'entity_test',
+      'entity_id' => $host->id(),
       'comment_type' => 'entity_test',
       'status' => 1,
     ]);
@@ -95,6 +99,7 @@ public function testCommentAuthorName() {
       'mail' => 'test@example.com',
       'homepage' => 'https://example.com',
       'entity_type' => 'entity_test',
+      'entity_id' => $host->id(),
       'comment_type' => 'entity_test',
       'status' => 1,
     ]);
diff --git a/core/modules/comment/tests/src/Kernel/Views/CommentLinksTest.php b/core/modules/comment/tests/src/Kernel/Views/CommentLinksTest.php
index ffb91b0688..08a326dde4 100644
--- a/core/modules/comment/tests/src/Kernel/Views/CommentLinksTest.php
+++ b/core/modules/comment/tests/src/Kernel/Views/CommentLinksTest.php
@@ -19,6 +19,13 @@
 class CommentLinksTest extends CommentViewsKernelTestBase {
 
   /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = ['entity_test'];
+
+  /**
    * Views used by this test.
    *
    * @var array
@@ -26,14 +33,26 @@ class CommentLinksTest extends CommentViewsKernelTestBase {
   public static $testViews = ['test_comment'];
 
   /**
+   * {@inheritdoc}
+   */
+  protected function setUp($import_test_views = TRUE) {
+    parent::setUp($import_test_views);
+
+    $this->installEntitySchema('entity_test');
+  }
+
+  /**
    * Test the comment approve link.
    */
   public function testLinkApprove() {
+    $host = EntityTest::create(['name' => $this->randomString()]);
+    $host->save();
 
     // Create an unapproved comment.
     $comment = $this->commentStorage->create([
       'uid' => $this->adminUser->id(),
       'entity_type' => 'entity_test',
+      'entity_id' => $host->id(),
       'comment_type' => 'entity_test',
       'status' => 0,
     ]);
@@ -91,8 +110,7 @@ public function testLinkApprove() {
    * Test the comment reply link.
    */
   public function testLinkReply() {
-    $this->enableModules(['field', 'entity_test']);
-    $this->installEntitySchema('entity_test');
+    $this->enableModules(['field']);
     $this->installSchema('comment', ['comment_entity_statistics']);
     $this->installConfig(['field']);
 
diff --git a/core/modules/comment/tests/src/Kernel/Views/CommentUserNameTest.php b/core/modules/comment/tests/src/Kernel/Views/CommentUserNameTest.php
index e1b3c94336..2fb8c74570 100644
--- a/core/modules/comment/tests/src/Kernel/Views/CommentUserNameTest.php
+++ b/core/modules/comment/tests/src/Kernel/Views/CommentUserNameTest.php
@@ -4,6 +4,7 @@
 
 use Drupal\comment\Entity\Comment;
 use Drupal\Core\Session\AnonymousUserSession;
+use Drupal\entity_test\Entity\EntityTest;
 use Drupal\Tests\views\Kernel\ViewsKernelTestBase;
 use Drupal\user\Entity\Role;
 use Drupal\user\Entity\User;
@@ -36,6 +37,7 @@ protected function setUp($import_test_views = TRUE) {
 
     $this->installEntitySchema('user');
     $this->installEntitySchema('comment');
+    $this->installEntitySchema('entity_test');
     // Create the anonymous role.
     $this->installConfig(['user']);
 
@@ -67,12 +69,16 @@ protected function setUp($import_test_views = TRUE) {
     ]);
     $this->adminUser->save();
 
+    $host = EntityTest::create(['name' => $this->randomString()]);
+    $host->save();
+
     // Create some comments.
     $comment = Comment::create([
       'subject' => 'My comment title',
       'uid' => $this->adminUser->id(),
       'name' => $this->adminUser->label(),
       'entity_type' => 'entity_test',
+      'entity_id' => $host->id(),
       'comment_type' => 'entity_test',
       'status' => 1,
     ]);
@@ -85,6 +91,7 @@ protected function setUp($import_test_views = TRUE) {
       'mail' => 'test@example.com',
       'homepage' => 'https://example.com',
       'entity_type' => 'entity_test',
+      'entity_id' => $host->id(),
       'comment_type' => 'entity_test',
       'created' => 123456,
       'status' => 1,
diff --git a/core/modules/comment/tests/src/Kernel/Views/CommentViewsFieldAccessTest.php b/core/modules/comment/tests/src/Kernel/Views/CommentViewsFieldAccessTest.php
index f807c58d82..1ca5e43971 100644
--- a/core/modules/comment/tests/src/Kernel/Views/CommentViewsFieldAccessTest.php
+++ b/core/modules/comment/tests/src/Kernel/Views/CommentViewsFieldAccessTest.php
@@ -3,6 +3,7 @@
 namespace Drupal\Tests\comment\Kernel\Views;
 
 use Drupal\comment\Entity\Comment;
+use Drupal\entity_test\Entity\EntityTest;
 use Drupal\user\Entity\User;
 use Drupal\Tests\views\Kernel\Handler\FieldFieldAccessTestBase;
 
@@ -25,6 +26,7 @@ protected function setUp($import_test_views = TRUE) {
     parent::setUp($import_test_views);
 
     $this->installEntitySchema('comment');
+    $this->installEntitySchema('entity_test');
   }
 
   /**
@@ -36,10 +38,14 @@ public function testCommentFields() {
     ]);
     $user->save();
 
+    $host = EntityTest::create(['name' => $this->randomString()]);
+    $host->save();
+
     $comment = Comment::create([
       'subject' => 'My comment title',
       'uid' => $user->id(),
       'entity_type' => 'entity_test',
+      'entity_id' => $host->id(),
       'comment_type' => 'entity_test',
     ]);
     $comment->save();
@@ -51,6 +57,7 @@ public function testCommentFields() {
       'mail' => 'test@example.com',
       'homepage' => 'https://example.com',
       'entity_type' => 'entity_test',
+      'entity_id' => $host->id(),
       'comment_type' => 'entity_test',
       'created' => 123456,
       'status' => 1,
diff --git a/core/modules/content_moderation/src/Entity/ContentModerationState.php b/core/modules/content_moderation/src/Entity/ContentModerationState.php
index e54fbbe2a8..14fb5e7276 100644
--- a/core/modules/content_moderation/src/Entity/ContentModerationState.php
+++ b/core/modules/content_moderation/src/Entity/ContentModerationState.php
@@ -65,13 +65,15 @@ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
       ->setLabel(t('Workflow'))
       ->setDescription(t('The workflow the moderation state is in.'))
       ->setSetting('target_type', 'workflow')
-      ->setRequired(TRUE)
+      // @todo Make this field required in https://www.drupal.org/node/2871036.
+      // ->setRequired(TRUE)
       ->setRevisionable(TRUE);
 
     $fields['moderation_state'] = BaseFieldDefinition::create('string')
       ->setLabel(t('Moderation state'))
       ->setDescription(t('The moderation state of the referenced content.'))
-      ->setRequired(TRUE)
+      // @todo Make this field required in https://www.drupal.org/node/2871036.
+      // ->setRequired(TRUE)
       ->setTranslatable(TRUE)
       ->setRevisionable(TRUE);
 
diff --git a/core/modules/content_moderation/tests/src/Kernel/ContentModerationStateTest.php b/core/modules/content_moderation/tests/src/Kernel/ContentModerationStateTest.php
index e52bf96137..00e364419a 100644
--- a/core/modules/content_moderation/tests/src/Kernel/ContentModerationStateTest.php
+++ b/core/modules/content_moderation/tests/src/Kernel/ContentModerationStateTest.php
@@ -72,59 +72,12 @@ protected function setUp() {
   }
 
   /**
-   * Sets up a bundle entity type for the specified entity type, if needed.
-   *
-   * @param string $entity_type_id
-   *   The entity type identifier.
-   *
-   * @return string
-   *   The bundle identifier.
-   */
-  protected function setupBundleEntityType($entity_type_id) {
-    $bundle_id = $entity_type_id;
-    $bundle_entity_type_id = $this->entityTypeManager->getDefinition($entity_type_id)->getBundleEntityType();
-    if ($bundle_entity_type_id) {
-      $bundle_entity_type_definition = $this->entityTypeManager->getDefinition($bundle_entity_type_id);
-      $entity_type_storage = $this->entityTypeManager->getStorage($bundle_entity_type_id);
-
-      $entity_type = $entity_type_storage->create([
-        $bundle_entity_type_definition->getKey('id') => 'example',
-      ]);
-      if ($entity_type_id == 'media') {
-        $entity_type->set('source', 'test');
-        $entity_type->save();
-        $source_field = $entity_type->getSource()->createSourceField($entity_type);
-        $source_field->getFieldStorageDefinition()->save();
-        $source_field->save();
-        $entity_type->set('source_configuration', [
-          'source_field' => $source_field->getName(),
-        ]);
-      }
-      $entity_type->save();
-      $bundle_id = $entity_type->id();
-    }
-
-    $workflow = Workflow::load('editorial');
-    $workflow->getTypePlugin()->addEntityTypeAndBundle($entity_type_id, $bundle_id);
-    $workflow->save();
-
-    return $bundle_id;
-  }
-
-  /**
    * Tests basic monolingual content moderation through the API.
    *
    * @dataProvider basicModerationTestCases
    */
   public function testBasicModeration($entity_type_id) {
-    $bundle_id = $this->setupBundleEntityType($entity_type_id);
-
-    /** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
-    $entity_storage = $this->entityTypeManager->getStorage($entity_type_id);
-    $entity = $entity_storage->create([
-      'title' => 'Test title',
-      $this->entityTypeManager->getDefinition($entity_type_id)->getKey('bundle') => $bundle_id,
-    ]);
+    $entity = $this->createEntity($entity_type_id);
     if ($entity instanceof EntityPublishedInterface) {
       $entity->setUnpublished();
     }
@@ -175,6 +128,7 @@ public function testBasicModeration($entity_type_id) {
     $entity->save();
 
     // Revert to the previous (published) revision.
+    $entity_storage = $this->entityTypeManager->getStorage($entity_type_id);
     $previous_revision = $entity_storage->loadRevision(4);
     $previous_revision->isDefaultRevision(TRUE);
     $previous_revision->setNewRevision(TRUE);
@@ -225,15 +179,9 @@ public function basicModerationTestCases() {
    * @dataProvider basicModerationTestCases
    */
   public function testContentModerationStateDataRemoval($entity_type_id) {
-    $bundle_id = $this->setupBundleEntityType($entity_type_id);
-
     // Test content moderation state deletion.
-    $entity_storage = $this->entityTypeManager->getStorage($entity_type_id);
     /** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
-    $entity = $entity_storage->create([
-      'title' => 'Test title',
-      $this->entityTypeManager->getDefinition($entity_type_id)->getKey('bundle') => $bundle_id,
-    ]);
+    $entity = $this->createEntity($entity_type_id);
     $entity->save();
     $entity = $this->reloadEntity($entity);
     $entity->delete();
@@ -242,10 +190,7 @@ public function testContentModerationStateDataRemoval($entity_type_id) {
 
     // Test content moderation state revision deletion.
     /** @var \Drupal\Core\Entity\ContentEntityInterface $entity2 */
-    $entity2 = $entity_storage->create([
-      'title' => 'Test title',
-      $this->entityTypeManager->getDefinition($entity_type_id)->getKey('bundle') => $bundle_id,
-    ]);
+    $entity2 = $this->createEntity($entity_type_id);
     $entity2->save();
     $revision = clone $entity2;
     $revision->isDefaultRevision(FALSE);
@@ -254,6 +199,7 @@ public function testContentModerationStateDataRemoval($entity_type_id) {
     $entity2 = $this->reloadEntity($entity2);
     $entity2->setNewRevision(TRUE);
     $entity2->save();
+    $entity_storage = $this->entityTypeManager->getStorage($entity_type_id);
     $entity_storage->deleteRevision($revision->getRevisionId());
     $content_moderation_state = ContentModerationState::loadFromModeratedEntity($revision);
     $this->assertFalse($content_moderation_state);
@@ -263,15 +209,16 @@ public function testContentModerationStateDataRemoval($entity_type_id) {
     // Test content moderation state translation deletion.
     if ($this->entityTypeManager->getDefinition($entity_type_id)->isTranslatable()) {
       /** @var \Drupal\Core\Entity\ContentEntityInterface $entity3 */
-      $entity3 = $entity_storage->create([
-        'title' => 'Test title',
-        $this->entityTypeManager->getDefinition($entity_type_id)->getKey('bundle') => $bundle_id,
-      ]);
+      $entity3 = $this->createEntity($entity_type_id);
       $langcode = 'it';
       ConfigurableLanguage::createFromLangcode($langcode)
         ->save();
       $entity3->save();
       $translation = $entity3->addTranslation($langcode, ['title' => 'Titolo test']);
+      // Make sure we add values for all of the required fields.
+      if ($entity_type_id == 'block_content') {
+        $translation->info = $this->randomString();
+      }
       $translation->save();
       $content_moderation_state = ContentModerationState::loadFromModeratedEntity($entity3);
       $this->assertTrue($content_moderation_state->hasTranslation($langcode));
@@ -590,6 +537,63 @@ public function testWorkflowNonConfigBundleDependencies() {
   }
 
   /**
+   * Creates an entity.
+   *
+   * The entity will have required fields populated and the corresponding bundle
+   * will be enabled for content moderation.
+   *
+   * @param string $entity_type_id
+   *   The entity type ID.
+   *
+   * @return \Drupal\Core\Entity\ContentEntityInterface
+   *   The created entity.
+   */
+  protected function createEntity($entity_type_id) {
+    $entity_type = $this->entityTypeManager->getDefinition($entity_type_id);
+
+    $bundle_id = $entity_type_id;
+    // Set up a bundle entity type for the specified entity type, if needed.
+    if ($bundle_entity_type_id = $entity_type->getBundleEntityType()) {
+      $bundle_entity_type = $this->entityTypeManager->getDefinition($bundle_entity_type_id);
+      $bundle_entity_storage = $this->entityTypeManager->getStorage($bundle_entity_type_id);
+
+      $bundle_id = 'example';
+      if (!$bundle_entity_storage->load($bundle_id)) {
+        $bundle_entity = $bundle_entity_storage->create([
+          $bundle_entity_type->getKey('id') => 'example',
+        ]);
+        if ($entity_type_id == 'media') {
+          $bundle_entity->set('source', 'test');
+          $bundle_entity->save();
+          $source_field = $bundle_entity->getSource()->createSourceField($bundle_entity);
+          $source_field->getFieldStorageDefinition()->save();
+          $source_field->save();
+          $bundle_entity->set('source_configuration', [
+            'source_field' => $source_field->getName(),
+          ]);
+        }
+        $bundle_entity->save();
+      }
+    }
+
+    $workflow = Workflow::load('editorial');
+    $workflow->getTypePlugin()->addEntityTypeAndBundle($entity_type_id, $bundle_id);
+    $workflow->save();
+
+    /** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
+    $entity_storage = $this->entityTypeManager->getStorage($entity_type_id);
+    $entity = $entity_storage->create([
+      $entity_type->getKey('label') => 'Test title',
+      $entity_type->getKey('bundle') => $bundle_id,
+    ]);
+    // Make sure we add values for all of the required fields.
+    if ($entity_type_id == 'block_content') {
+      $entity->info = $this->randomString();
+    }
+    return $entity;
+  }
+
+  /**
    * Reloads the entity after clearing the static cache.
    *
    * @param \Drupal\Core\Entity\EntityInterface $entity
diff --git a/core/modules/menu_link_content/tests/src/Functional/LinksTest.php b/core/modules/menu_link_content/tests/src/Functional/LinksTest.php
index 6a3d50b319..298af6fae3 100644
--- a/core/modules/menu_link_content/tests/src/Functional/LinksTest.php
+++ b/core/modules/menu_link_content/tests/src/Functional/LinksTest.php
@@ -127,6 +127,7 @@ public function testCreateLink() {
       'menu_name' => 'menu_test',
       'bundle' => 'menu_link_content',
       'link' => [['uri' => 'internal:/']],
+      'title' => 'Link test',
     ];
     $link = MenuLinkContent::create($options);
     $link->save();
@@ -148,7 +149,12 @@ public function testCreateLink() {
   public function testMenuLinkOnEntityDelete() {
     $user = User::create(['name' => 'username']);
     $user->save();
-    $menu_link_content = MenuLinkContent::create(['menu_name' => 'menu_test', 'link' => [['uri' => 'entity:user/' . $user->id()]], 'bundle' => 'menu_test']);
+    $menu_link_content = MenuLinkContent::create([
+      'title' => 'username profile',
+      'menu_name' => 'menu_test',
+      'link' => [['uri' => 'entity:user/' . $user->id()]],
+      'bundle' => 'menu_test',
+    ]);
     $menu_link_content->save();
     $menu_tree_condition = (new MenuTreeParameters())->addCondition('route_name', 'entity.user.canonical');
     $this->assertCount(1, \Drupal::menuTree()->load('menu_test', $menu_tree_condition));
diff --git a/core/modules/menu_link_content/tests/src/Functional/MenuLinkContentTranslationUITest.php b/core/modules/menu_link_content/tests/src/Functional/MenuLinkContentTranslationUITest.php
index a2ba9930fc..b208427fb8 100644
--- a/core/modules/menu_link_content/tests/src/Functional/MenuLinkContentTranslationUITest.php
+++ b/core/modules/menu_link_content/tests/src/Functional/MenuLinkContentTranslationUITest.php
@@ -70,7 +70,7 @@ public function testTranslationLinkOnMenuEditForm() {
     $this->drupalGet('admin/structure/menu/manage/tools');
     $this->assertNoLink(t('Translate'));
 
-    $menu_link_content = MenuLinkContent::create(['menu_name' => 'tools', 'link' => ['uri' => 'internal:/admin/structure/menu']]);
+    $menu_link_content = MenuLinkContent::create(['menu_name' => 'tools', 'link' => ['uri' => 'internal:/admin/structure/menu'], 'title' => 'Link test']);
     $menu_link_content->save();
     $this->drupalGet('admin/structure/menu/manage/tools');
     $this->assertLink(t('Translate'));
diff --git a/core/modules/menu_link_content/tests/src/Kernel/MenuLinkContentCacheabilityBubblingTest.php b/core/modules/menu_link_content/tests/src/Kernel/MenuLinkContentCacheabilityBubblingTest.php
index 414ecdeb0d..118470fa12 100644
--- a/core/modules/menu_link_content/tests/src/Kernel/MenuLinkContentCacheabilityBubblingTest.php
+++ b/core/modules/menu_link_content/tests/src/Kernel/MenuLinkContentCacheabilityBubblingTest.php
@@ -108,6 +108,7 @@ public function testOutboundPathAndRouteProcessing() {
       $menu_link_content = MenuLinkContent::create([
         'link' => ['uri' => $expectation['uri']],
         'menu_name' => 'tools',
+        'title' => 'Link test',
       ]);
       $menu_link_content->save();
       $tree = $menu_tree->load('tools', new MenuTreeParameters());
@@ -128,6 +129,7 @@ public function testOutboundPathAndRouteProcessing() {
       $menu_link_content = MenuLinkContent::create([
         'link' => ['uri' => $expectation['uri']],
         'menu_name' => 'tools',
+        'title' => 'Link test',
       ]);
       $menu_link_content->save();
       $expected_cacheability = $expected_cacheability->merge($expectation['cacheability']);
diff --git a/core/modules/migrate/src/Plugin/migrate/destination/EntityContentBase.php b/core/modules/migrate/src/Plugin/migrate/destination/EntityContentBase.php
index cf3ae1dedb..5afe173aa3 100644
--- a/core/modules/migrate/src/Plugin/migrate/destination/EntityContentBase.php
+++ b/core/modules/migrate/src/Plugin/migrate/destination/EntityContentBase.php
@@ -218,7 +218,7 @@ protected function processStubRow(Row $row) {
       if ($field_definition->isRequired() && is_null($row->getDestinationProperty($field_name))) {
         // Use the configured default value for this specific field, if any.
         if ($default_value = $field_definition->getDefaultValueLiteral()) {
-          $values[] = $default_value;
+          $values = reset($default_value);
         }
         else {
           // Otherwise, ask the field type to generate a sample value.
diff --git a/core/modules/node/node.install b/core/modules/node/node.install
index 6469245c49..5bfff43253 100644
--- a/core/modules/node/node.install
+++ b/core/modules/node/node.install
@@ -255,3 +255,16 @@ function node_update_8400() {
   $schema['fields']['realm']['description'] = 'The realm in which the user must possess the grant ID. Modules can define one or more realms by implementing hook_node_grants().';
   Database::getConnection()->schema()->changeField('node_access', 'realm', 'realm', $schema['fields']['realm']);
 }
+
+/**
+ * Update the 'uid' field in order to make it required at the storage level.
+ */
+function node_update_8501() {
+  // The SQL content entity schema no longer uses entity keys to mark their
+  // corresponding fields as NOT NULL in the database, so we need to update the
+  // 'uid' field manually.
+  $definition_update_manager = \Drupal::entityDefinitionUpdateManager();
+  $field_storage_definition = $definition_update_manager->getFieldStorageDefinition('uid', 'node');
+  $field_storage_definition->setStorageRequired(TRUE);
+  $definition_update_manager->updateFieldStorageDefinition($field_storage_definition);
+}
diff --git a/core/modules/node/src/Entity/Node.php b/core/modules/node/src/Entity/Node.php
index 368ce1b596..9d55a3f187 100644
--- a/core/modules/node/src/Entity/Node.php
+++ b/core/modules/node/src/Entity/Node.php
@@ -320,6 +320,7 @@ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
     $fields['uid'] = BaseFieldDefinition::create('entity_reference')
       ->setLabel(t('Authored by'))
       ->setDescription(t('The username of the content author.'))
+      ->setStorageRequired(TRUE)
       ->setRevisionable(TRUE)
       ->setSetting('target_type', 'user')
       ->setDefaultValueCallback('Drupal\node\Entity\Node::getCurrentUserId')
diff --git a/core/modules/node/src/NodeStorageSchema.php b/core/modules/node/src/NodeStorageSchema.php
index ac45bb5d1e..c3b2ff274c 100644
--- a/core/modules/node/src/NodeStorageSchema.php
+++ b/core/modules/node/src/NodeStorageSchema.php
@@ -35,7 +35,7 @@ protected function getSharedTableFieldSchema(FieldStorageDefinitionInterface $st
     if ($table_name == 'node_revision') {
       switch ($field_name) {
         case 'langcode':
-          $this->addSharedTableFieldIndex($storage_definition, $schema, TRUE);
+          $this->addSharedTableFieldIndex($storage_definition, $schema);
           break;
 
         case 'revision_uid':
@@ -47,9 +47,7 @@ protected function getSharedTableFieldSchema(FieldStorageDefinitionInterface $st
     if ($table_name == 'node_field_data') {
       switch ($field_name) {
         case 'promote':
-        case 'status':
         case 'sticky':
-        case 'title':
           // Improves the performance of the indexes defined
           // in getEntitySchema().
           $schema['fields'][$field_name]['not null'] = TRUE;
diff --git a/core/modules/system/src/Tests/Entity/EntityDefinitionTestTrait.php b/core/modules/system/src/Tests/Entity/EntityDefinitionTestTrait.php
index 3b1e7bd660..2498d9740b 100644
--- a/core/modules/system/src/Tests/Entity/EntityDefinitionTestTrait.php
+++ b/core/modules/system/src/Tests/Entity/EntityDefinitionTestTrait.php
@@ -24,6 +24,7 @@ protected function enableNewEntityType() {
    */
   protected function resetEntityType() {
     $this->state->set('entity_test_update.entity_type', NULL);
+    $this->state->set('entity_test_update.required_field_storage_definitions', []);
     $this->entityManager->clearCachedDefinitions();
     $this->entityDefinitionUpdateManager->applyUpdates();
   }
@@ -40,6 +41,15 @@ protected function updateEntityTypeToRevisionable() {
     $entity_type->set('revision_table', 'entity_test_update_revision');
 
     $this->state->set('entity_test_update.entity_type', $entity_type);
+    $required_fields = [
+      $keys['id'],
+      $keys['uuid'],
+      $keys['revision'],
+    ];
+    if ($entity_type->isTranslatable()) {
+      $keys[] = $keys['langcode'];
+    }
+    $this->state->set('entity_test_update.required_field_storage_definitions', $required_fields);
   }
 
   /**
@@ -49,11 +59,16 @@ protected function updateEntityTypeToNotRevisionable() {
     $entity_type = clone $this->entityManager->getDefinition('entity_test_update');
 
     $keys = $entity_type->getKeys();
+
+    $required_fields = $this->state->get('entity_test_update.required_field_storage_definitions');
+    $required_fields = array_diff($required_fields, [$keys['revision']]);
+
     unset($keys['revision']);
     $entity_type->set('entity_keys', $keys);
     $entity_type->set('revision_table', NULL);
 
     $this->state->set('entity_test_update.entity_type', $entity_type);
+    $this->state->set('entity_test_update.required_field_storage_definitions', $required_fields);
   }
 
   /**
@@ -65,11 +80,21 @@ protected function updateEntityTypeToTranslatable() {
     $entity_type->set('translatable', TRUE);
     $entity_type->set('data_table', 'entity_test_update_data');
 
+    $keys = $entity_type->getKeys();
+    $required_fields = [
+      $keys['id'],
+      $keys['uuid'],
+      $keys['langcode'],
+    ];
+
     if ($entity_type->isRevisionable()) {
       $entity_type->set('revision_data_table', 'entity_test_update_revision_data');
+
+      $required_fields[] = $keys['revision'];
     }
 
     $this->state->set('entity_test_update.entity_type', $entity_type);
+    $this->state->set('entity_test_update.required_field_storage_definitions', $required_fields);
   }
 
   /**
@@ -104,6 +129,13 @@ protected function updateEntityTypeToRevisionableAndTranslatable() {
     $entity_type->set('revision_data_table', 'entity_test_update_revision_data');
 
     $this->state->set('entity_test_update.entity_type', $entity_type);
+
+    $this->state->set('entity_test_update.required_field_storage_definitions', [
+      $keys['id'],
+      $keys['uuid'],
+      $keys['revision'],
+      $keys['langcode'],
+    ]);
   }
 
   /**
@@ -156,13 +188,28 @@ protected function modifyBaseField() {
 
   /**
    * Promotes a field to an entity key.
+   *
+   * @deprecated in Drupal 8.4.0 and will be removed before Drupal 9.0.0. Use
+   *   \Drupal\system\Tests\Entity\EntityDefinitionTestTrait::makeBaseFieldRequired()
+   *   instead.
+   *
+   * This method has been deprecated because its intended usage was to mark a
+   * base field as an entity key in order to force the storage to mark it as
+   * NOT NULL. Starting with Drupal 8.4.0, only required (or storage-required)
+   * fields are marked as NOT NULL, so this method does not serve its initial
+   * purpose anymore.
    */
   protected function makeBaseFieldEntityKey() {
-    $entity_type = clone $this->entityManager->getDefinition('entity_test_update');
-    $entity_keys = $entity_type->getKeys();
-    $entity_keys['new_base_field'] = 'new_base_field';
-    $entity_type->set('entity_keys', $entity_keys);
-    $this->state->set('entity_test_update.entity_type', $entity_type);
+    $this->makeBaseFieldRequired();
+  }
+
+  /**
+   * Makes a base field required.
+   */
+  protected function makeBaseFieldRequired() {
+    $definitions = \Drupal::state()->get('entity_test_update.additional_base_field_definitions', []);
+    $definitions['new_base_field']->setRequired(TRUE);
+    $this->state->set('entity_test_update.additional_base_field_definitions', $definitions);
   }
 
   /**
diff --git a/core/modules/system/src/Tests/Update/EntityUpdateFilledTest.php b/core/modules/system/src/Tests/Update/EntityUpdateFilledTest.php
new file mode 100644
index 0000000000..5ac0688ce5
--- /dev/null
+++ b/core/modules/system/src/Tests/Update/EntityUpdateFilledTest.php
@@ -0,0 +1,23 @@
+<?php
+
+namespace Drupal\system\Tests\Update;
+
+/**
+ * Tests the upgrade path with existing data for various entity update issues.
+ *
+ * @see https://www.drupal.org/node/2841291
+ *
+ * @group Update
+ */
+class EntityUpdateFilledTest extends EntityUpdateTest {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setDatabaseDumpFiles() {
+    $this->databaseDumpFiles = [
+      __DIR__ . '/../../../../system/tests/fixtures/update/drupal-8.filled.standard.php.gz',
+    ];
+  }
+
+}
diff --git a/core/modules/system/src/Tests/Update/EntityUpdateTest.php b/core/modules/system/src/Tests/Update/EntityUpdateTest.php
new file mode 100644
index 0000000000..5012d0441f
--- /dev/null
+++ b/core/modules/system/src/Tests/Update/EntityUpdateTest.php
@@ -0,0 +1,62 @@
+<?php
+
+namespace Drupal\system\Tests\Update;
+
+/**
+ * Tests the upgrade path for various entity update issues.
+ *
+ * @see https://www.drupal.org/node/2841291
+ *
+ * @group Update
+ */
+class EntityUpdateTest extends UpdatePathTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setDatabaseDumpFiles() {
+    $this->databaseDumpFiles = [
+      __DIR__ . '/../../../../system/tests/fixtures/update/drupal-8.bare.standard.php.gz',
+    ];
+  }
+
+  /**
+   * Tests system_update_8501().
+   */
+  public function testSystemUpdate8501() {
+    // The installed field storage schema is wrong before running the update.
+    $key_value_store = \Drupal::keyValue('entity.storage_schema.sql');
+    $id_schema = $key_value_store->get('node.field_schema_data.nid', []);
+    $revision_id_schema = $key_value_store->get('node.field_schema_data.vid', []);
+
+    $this->assertEqual('int', $id_schema['node']['fields']['nid']['type']);
+    $this->assertEqual('int', $id_schema['node_revision']['fields']['nid']['type']);
+    $this->assertEqual('int', $revision_id_schema['node']['fields']['vid']['type']);
+    $this->assertEqual('int', $revision_id_schema['node_revision']['fields']['vid']['type']);
+
+    $this->runUpdates();
+
+    // Now check that the schema has been corrected.
+    $id_schema = $key_value_store->get('node.field_schema_data.nid', []);
+    $revision_id_schema = $key_value_store->get('node.field_schema_data.vid', []);
+
+    $this->assertEqual('serial', $id_schema['node']['fields']['nid']['type']);
+    $this->assertEqual('int', $id_schema['node_revision']['fields']['nid']['type']);
+    $this->assertEqual('int', $revision_id_schema['node']['fields']['vid']['type']);
+    $this->assertEqual('serial', $revision_id_schema['node_revision']['fields']['vid']['type']);
+
+    // Check that creating and loading a node still works as expected.
+    $node_storage = \Drupal::entityTypeManager()->getStorage('node');
+    $node = $node_storage->create([
+      'title' => 'Test update',
+      'type' => 'article',
+    ]);
+    $node->save();
+
+    $node_storage->resetCache();
+
+    $node = $node_storage->load($node->id());
+    $this->assertEqual('Test update', $node->label());
+  }
+
+}
diff --git a/core/modules/system/system.install b/core/modules/system/system.install
index ce48afe725..af5bbe986b 100644
--- a/core/modules/system/system.install
+++ b/core/modules/system/system.install
@@ -14,10 +14,11 @@
 use Drupal\Core\Path\AliasStorage;
 use Drupal\Core\Url;
 use Drupal\Core\Database\Database;
+use Drupal\Core\DrupalKernel;
 use Drupal\Core\Entity\ContentEntityTypeInterface;
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Entity\FieldableEntityInterface;
-use Drupal\Core\DrupalKernel;
+use Drupal\Core\Entity\Sql\SqlEntityStorageInterface;
 use Drupal\Core\Field\BaseFieldDefinition;
 use Drupal\Core\Site\Settings;
 use Drupal\Core\StreamWrapper\PrivateStream;
@@ -2043,3 +2044,48 @@ function system_update_8403() {
     }
   }
 }
+
+/**
+ * Correct the installed schema and NOT NULL handling for required base fields.
+ */
+function system_update_8501() {
+  $entity_type_manager = \Drupal::entityTypeManager();
+  $definition_update_manager = \Drupal::entityDefinitionUpdateManager();
+  /** @var \Drupal\Core\Entity\EntityLastInstalledSchemaRepositoryInterface $entity_last_installed_schema_respository */
+  $entity_last_installed_schema_respository = \Drupal::service('entity.last_installed_schema.repository');
+
+  foreach ($entity_type_manager->getDefinitions() as $entity_type_id => $entity_type) {
+    $original_entity_type = $entity_last_installed_schema_respository->getLastInstalledDefinition($entity_type_id);
+    $storage = $entity_type_manager->getStorage($entity_type_id);
+    if ($storage instanceof SqlEntityStorageInterface) {
+      foreach ($entity_last_installed_schema_respository->getLastInstalledFieldStorageDefinitions($entity_type_id) as $field_name => $field_definition) {
+        /** @var \Drupal\Core\Field\BaseFieldDefinition $field_definition */
+        if ($field_definition instanceof BaseFieldDefinition) {
+          $field_name = $field_definition->getName();
+
+          // The SQL content entity schema no longer uses entity keys to mark
+          // their corresponding fields as NOT NULL in the database, so we need
+          // to update them manually.
+          $entity_keys_names = [
+            $original_entity_type->getKey('id'),
+            $original_entity_type->getKey('uuid'),
+            $original_entity_type->getKey('revision'),
+            $original_entity_type->getKey('langcode'),
+            $original_entity_type->getKey('default_langcode'),
+          ];
+          if (in_array($field_name, $entity_keys_names)) {
+            $field_definition->setStorageRequired(TRUE);
+          }
+
+          if ($field_name == $original_entity_type->getKey('published')) {
+            $field_definition->setRequired(TRUE);
+          }
+
+          if ($field_definition->isStorageRequired()) {
+            $definition_update_manager->updateFieldStorageDefinition($field_definition);
+          }
+        }
+      }
+    }
+  }
+}
diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMulRevChanged.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMulRevChanged.php
index 391307576e..a3fb47ec55 100644
--- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMulRevChanged.php
+++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMulRevChanged.php
@@ -58,6 +58,7 @@ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
       ->setLabel(t('Revision ID'))
       ->setDescription(t('The version id of the test entity.'))
       ->setReadOnly(TRUE)
+      ->setStorageRequired(TRUE)
       ->setSetting('unsigned', TRUE);
 
     $fields['revision_translation_affected'] = BaseFieldDefinition::create('boolean')
diff --git a/core/modules/system/tests/modules/entity_test_update/entity_test_update.module b/core/modules/system/tests/modules/entity_test_update/entity_test_update.module
index bd674dd7a6..4b9443f8e9 100644
--- a/core/modules/system/tests/modules/entity_test_update/entity_test_update.module
+++ b/core/modules/system/tests/modules/entity_test_update/entity_test_update.module
@@ -30,6 +30,17 @@ function entity_test_update_entity_base_field_info(EntityTypeInterface $entity_t
 }
 
 /**
+ * Implements hook_entity_base_field_info_alter().
+ */
+function entity_test_update_entity_base_field_info_alter(&$fields, EntityTypeInterface $entity_type) {
+  if ($entity_type->id() === 'entity_test_update') {
+    foreach (\Drupal::state()->get('entity_test_update.required_field_storage_definitions', []) as $field_name) {
+      $fields[$field_name]->setStorageRequired(TRUE);
+    }
+  }
+}
+
+/**
  * Implements hook_entity_field_storage_info().
  */
 function entity_test_update_entity_field_storage_info(EntityTypeInterface $entity_type) {
diff --git a/core/modules/system/tests/src/Functional/Entity/Update/SqlContentEntityStorageSchemaConverterTest.php b/core/modules/system/tests/src/Functional/Entity/Update/SqlContentEntityStorageSchemaConverterTest.php
index 625ee190ed..d7799e6902 100644
--- a/core/modules/system/tests/src/Functional/Entity/Update/SqlContentEntityStorageSchemaConverterTest.php
+++ b/core/modules/system/tests/src/Functional/Entity/Update/SqlContentEntityStorageSchemaConverterTest.php
@@ -17,6 +17,11 @@ class SqlContentEntityStorageSchemaConverterTest extends UpdatePathTestBase {
   use EntityDefinitionTestTrait;
 
   /**
+   * {@inheritdoc}
+   */
+  protected static $modules = ['block_content'];
+
+  /**
    * The entity manager service.
    *
    * @var \Drupal\Core\Entity\EntityManagerInterface
@@ -219,7 +224,24 @@ public function testMakeRevisionableErrorHandling() {
 
     foreach ($new_storage_definitions as $storage_definition) {
       $new_field_schema_data[$storage_definition->getName()] = $this->installedStorageSchema->get('entity_test_update.field_schema_data.' . $storage_definition->getName(), []);
+      // Ignore the fact that the field schema now contains defaults for DX.
+      foreach ($new_field_schema_data[$storage_definition->getName()] as $table_name => $field_table_schema) {
+        foreach (['unique keys', 'indexes', 'foreign keys'] as $key) {
+          if (isset($field_table_schema[$key]) && ($field_table_schema[$key] === [])) {
+            $original_field_schema_data[$storage_definition->getName()][$table_name] += [
+              $key => [],
+            ];
+          }
+        }
+      }
     }
+    // Before https://www.drupal.org/project/drupal/issues/2841291 the field
+    // schema data of integer identifier fields was incorrectly stored as 'int'
+    // instead of 'serial'. So we explicitly make that change before checking
+    // equality.
+    /* @see \Drupal\Core\Entity\Sql\SqlContentEntityStorageSchema::hasColumnChanges() */
+    $this->assertSame($original_field_schema_data['id']['entity_test_update']['fields']['id']['type'], 'int');
+    $original_field_schema_data['id']['entity_test_update']['fields']['id']['type'] = 'serial';
     $this->assertEqual($original_field_schema_data, $new_field_schema_data);
 
     // Check that temporary tables have been removed.
diff --git a/core/modules/system/tests/src/Functional/Update/EntityUpdateInitialTest.php b/core/modules/system/tests/src/Functional/Update/EntityUpdateInitialTest.php
index d4d79f96b5..d940480eae 100644
--- a/core/modules/system/tests/src/Functional/Update/EntityUpdateInitialTest.php
+++ b/core/modules/system/tests/src/Functional/Update/EntityUpdateInitialTest.php
@@ -27,6 +27,13 @@ protected function setDatabaseDumpFiles() {
    * Tests that a pre-existing initial key in the field schema is not a change.
    */
   public function testInitialIsIgnored() {
+    $entity_type = \Drupal::entityTypeManager()->getDefinition('entity_test_update');
+    $keys = $entity_type->getKeys();
+    \Drupal::state()->set('entity_test_update.required_field_storage_definitions', [
+      $keys['id'],
+      $keys['uuid'],
+      $keys['langcode'],
+    ]);
     $this->runUpdates();
   }
 
diff --git a/core/modules/system/tests/src/Functional/Update/EntityUpdateToRevisionableAndPublishableTest.php b/core/modules/system/tests/src/Functional/Update/EntityUpdateToRevisionableAndPublishableTest.php
index e72f9f1b55..a3d520ec36 100644
--- a/core/modules/system/tests/src/Functional/Update/EntityUpdateToRevisionableAndPublishableTest.php
+++ b/core/modules/system/tests/src/Functional/Update/EntityUpdateToRevisionableAndPublishableTest.php
@@ -178,7 +178,7 @@ protected function updateEntityTypeDefinition() {
       ->setDescription(t('A boolean indicating the published state.'))
       ->setRevisionable(TRUE)
       ->setTranslatable(TRUE)
-      ->setRequired(TRUE)
+      ->setStorageRequired(TRUE)
       ->setDefaultValue(TRUE);
 
     $revision_created = BaseFieldDefinition::create('created')
@@ -211,6 +211,12 @@ protected function updateEntityTypeDefinition() {
       'revision_user' => $revision_user,
       'revision_log_message' => $revision_log_message,
     ]);
+    $this->state->set('entity_test_update.required_field_storage_definitions', [
+      $keys['id'],
+      $keys['uuid'],
+      $keys['revision'],
+      $keys['langcode'],
+    ]);
 
     $this->entityTypeManager->clearCachedDefinitions();
   }
diff --git a/core/modules/user/src/UserStorageSchema.php b/core/modules/user/src/UserStorageSchema.php
index 5e590b8958..35b158105f 100644
--- a/core/modules/user/src/UserStorageSchema.php
+++ b/core/modules/user/src/UserStorageSchema.php
@@ -44,9 +44,6 @@ protected function getSharedTableFieldSchema(FieldStorageDefinitionInterface $st
     if ($table_name == 'users_field_data') {
       switch ($field_name) {
         case 'name':
-          // Improves the performance of the user__name index defined
-          // in getEntitySchema().
-          $schema['fields'][$field_name]['not null'] = TRUE;
           // Make sure the field is no longer than 191 characters so we can
           // add a unique constraint in MySQL.
           $schema['fields'][$field_name]['length'] = USERNAME_MAX_LENGTH;
diff --git a/core/tests/Drupal/KernelTests/Core/Entity/EntityDefinitionUpdateTest.php b/core/tests/Drupal/KernelTests/Core/Entity/EntityDefinitionUpdateTest.php
index d0f5a1cd7b..daf9f94619 100644
--- a/core/tests/Drupal/KernelTests/Core/Entity/EntityDefinitionUpdateTest.php
+++ b/core/tests/Drupal/KernelTests/Core/Entity/EntityDefinitionUpdateTest.php
@@ -810,7 +810,7 @@ public function testSingleActionCalls() {
   /**
    * Ensures that a new field and index on a shared table are created.
    *
-   * @see Drupal\Core\Entity\Sql\SqlContentEntityStorageSchema::createSharedTableSchema
+   * @see \Drupal\Core\Entity\Sql\SqlContentEntityStorageSchema::createSharedTableSchema
    */
   public function testCreateFieldAndIndexOnSharedTable() {
     $this->addBaseField();
@@ -828,7 +828,7 @@ public function testCreateFieldAndIndexOnSharedTable() {
   /**
    * Ensures that a new entity level index is created when data exists.
    *
-   * @see Drupal\Core\Entity\Sql\SqlContentEntityStorageSchema::onEntityTypeUpdate
+   * @see \Drupal\Core\Entity\Sql\SqlContentEntityStorageSchema::onEntityTypeUpdate
    */
   public function testCreateIndexUsingEntityStorageSchemaWithData() {
     // Save an entity.
@@ -867,14 +867,14 @@ public function testBaseFieldEntityKeyUpdateWithExistingData() {
     $entity = $this->entityManager->getStorage('entity_test_update')->create();
     $entity->save();
 
-    // Promote the base field to an entity key. This will trigger the addition
-    // of a NOT NULL constraint.
-    $this->makeBaseFieldEntityKey();
+    // Make the base field required. This will trigger the addition of a NOT
+    // NULL constraint.
+    $this->makeBaseFieldRequired();
 
     // Field storage CRUD operations use the last installed entity type
     // definition so we need to update it before doing any other field storage
     // updates.
-    $this->entityDefinitionUpdateManager->updateEntityType($this->state->get('entity_test_update.entity_type'));
+    $this->entityDefinitionUpdateManager->updateEntityType($this->entityManager->getDefinition('entity_test_update'));
 
     // Try to apply the update and verify they fail since we have a NULL value.
     $message = 'An error occurs when trying to enabling NOT NULL constraints with NULL data.';
@@ -1032,4 +1032,51 @@ public function testInitialValueFromFieldErrorHandling() {
     }
   }
 
+  /**
+   * Checks that updating the main identifier field ('id') is correctly handled.
+   */
+  public function testUpdateIdentifierField() {
+    // Get the storage definition for an entity identifier, the 'id' field.
+    $storage_definition = $this->entityDefinitionUpdateManager->getFieldStorageDefinition('id', 'entity_test_update');
+
+    // Update the storage definition without any changes.
+    $this->entityDefinitionUpdateManager->updateFieldStorageDefinition($storage_definition);
+
+    // Check that creating, saving and loading an entity still works.
+    $storage = $this->entityManager->getStorage('entity_test_update');
+
+    $entity = $storage->create();
+    $entity->save();
+
+    $storage->resetCache();
+    $this->assertNotNull($storage->load($entity->id()));
+  }
+
+  /**
+   * Check that updating the revision identifier field is correctly handled.
+   */
+  public function testUpdateRevisionIdentifierField() {
+    $this->updateEntityTypeToRevisionable();
+    $this->entityDefinitionUpdateManager->applyUpdates();
+
+    // Get the storage definition for the revision identifier, the 'revision_id'
+    // field.
+    $storage_definition = $this->entityDefinitionUpdateManager->getFieldStorageDefinition('revision_id', 'entity_test_update');
+
+    // Update the storage definition without any changes.
+    $this->entityDefinitionUpdateManager->updateFieldStorageDefinition($storage_definition);
+
+    // Check that creating and saving an entity still works.
+    $this->entityManager->getStorage('entity_test_update')->create()->save();
+
+    // Check that creating, saving and loading an entity still works.
+    $storage = $this->entityManager->getStorage('entity_test_update');
+
+    $entity = $storage->create();
+    $entity->save();
+
+    $storage->resetCache();
+    $this->assertNotNull($storage->loadRevision($entity->getRevisionId()));
+  }
+
 }
diff --git a/core/tests/Drupal/KernelTests/Core/Entity/EntitySchemaTest.php b/core/tests/Drupal/KernelTests/Core/Entity/EntitySchemaTest.php
index 3e285ff69b..8141ae679c 100644
--- a/core/tests/Drupal/KernelTests/Core/Entity/EntitySchemaTest.php
+++ b/core/tests/Drupal/KernelTests/Core/Entity/EntitySchemaTest.php
@@ -5,9 +5,9 @@
 use Drupal\Component\Utility\SafeMarkup;
 
 /**
- * Tests adding a custom bundle field.
+ * Tests the default entity storage schema handler.
  *
- * @group system
+ * @group Entity
  */
 class EntitySchemaTest extends EntityKernelTestBase {
 
@@ -188,4 +188,63 @@ public function testCleanUpStorageDefinition() {
     $this->assertEqual($entity_type_id_count, 0, 'After uninstalling entity_test module the schema should not contains fields from entities provided by the module.');
   }
 
+  /**
+   * Tests the installed storage schema for identifier fields.
+   */
+  public function testIdentifierSchema() {
+    $this->installEntitySchema('entity_test_rev');
+
+    $key_value_store = \Drupal::keyValue('entity.storage_schema.sql');
+    $id_schema = $key_value_store->get('entity_test_rev.field_schema_data.id', []);
+    $revision_id_schema = $key_value_store->get('entity_test_rev.field_schema_data.revision_id', []);
+
+    $expected_id_schema = [
+      'entity_test_rev' => [
+        'fields' => [
+          'id' => [
+            'type' => 'serial',
+            'unsigned' => TRUE,
+            'size' => 'normal',
+            'not null' => TRUE,
+          ],
+        ],
+      ],
+      'entity_test_rev_revision' => [
+        'fields' => [
+          'id' => [
+            'type' => 'int',
+            'unsigned' => TRUE,
+            'size' => 'normal',
+            'not null' => TRUE,
+          ],
+        ],
+      ],
+    ];
+    $this->assertEquals($expected_id_schema, $id_schema);
+
+    $expected_revision_id_schema = [
+      'entity_test_rev' => [
+        'fields' => [
+          'revision_id' => [
+            'type' => 'int',
+            'unsigned' => TRUE,
+            'size' => 'normal',
+            'not null' => FALSE,
+          ],
+        ],
+      ],
+      'entity_test_rev_revision' => [
+        'fields' => [
+          'revision_id' => [
+            'type' => 'serial',
+            'unsigned' => TRUE,
+            'size' => 'normal',
+            'not null' => TRUE,
+          ],
+        ],
+      ],
+    ];
+    $this->assertEquals($expected_revision_id_schema, $revision_id_schema);
+  }
+
 }
diff --git a/core/tests/Drupal/KernelTests/Core/Menu/MenuLinkTreeTest.php b/core/tests/Drupal/KernelTests/Core/Menu/MenuLinkTreeTest.php
index 9bb7f5455d..04c04aa3e3 100644
--- a/core/tests/Drupal/KernelTests/Core/Menu/MenuLinkTreeTest.php
+++ b/core/tests/Drupal/KernelTests/Core/Menu/MenuLinkTreeTest.php
@@ -62,9 +62,9 @@ public function testDeleteLinksInMenu() {
     \Drupal::entityManager()->getStorage('menu')->create(['id' => 'menu1'])->save();
     \Drupal::entityManager()->getStorage('menu')->create(['id' => 'menu2'])->save();
 
-    \Drupal::entityManager()->getStorage('menu_link_content')->create(['link' => ['uri' => 'internal:/menu_name_test'], 'menu_name' => 'menu1', 'bundle' => 'menu_link_content'])->save();
-    \Drupal::entityManager()->getStorage('menu_link_content')->create(['link' => ['uri' => 'internal:/menu_name_test'], 'menu_name' => 'menu1', 'bundle' => 'menu_link_content'])->save();
-    \Drupal::entityManager()->getStorage('menu_link_content')->create(['link' => ['uri' => 'internal:/menu_name_test'], 'menu_name' => 'menu2', 'bundle' => 'menu_link_content'])->save();
+    \Drupal::entityManager()->getStorage('menu_link_content')->create(['link' => ['uri' => 'internal:/menu_name_test'], 'menu_name' => 'menu1', 'bundle' => 'menu_link_content', 'title' => 'Link test'])->save();
+    \Drupal::entityManager()->getStorage('menu_link_content')->create(['link' => ['uri' => 'internal:/menu_name_test'], 'menu_name' => 'menu1', 'bundle' => 'menu_link_content', 'title' => 'Link test'])->save();
+    \Drupal::entityManager()->getStorage('menu_link_content')->create(['link' => ['uri' => 'internal:/menu_name_test'], 'menu_name' => 'menu2', 'bundle' => 'menu_link_content', 'title' => 'Link test'])->save();
 
     $output = $this->linkTree->load('menu1', new MenuTreeParameters());
     $this->assertEqual(count($output), 2);
diff --git a/core/tests/Drupal/Tests/Core/Entity/Sql/SqlContentEntityStorageSchemaTest.php b/core/tests/Drupal/Tests/Core/Entity/Sql/SqlContentEntityStorageSchemaTest.php
index d16ece2097..e4564b41cc 100644
--- a/core/tests/Drupal/Tests/Core/Entity/Sql/SqlContentEntityStorageSchemaTest.php
+++ b/core/tests/Drupal/Tests/Core/Entity/Sql/SqlContentEntityStorageSchemaTest.php
@@ -74,6 +74,7 @@ protected function setUp() {
       'columns' => [
         'value' => [
           'type' => 'int',
+          'not null' => TRUE,
         ],
       ],
     ]);
@@ -397,7 +398,7 @@ public function testGetSchemaRevisionable() {
       ],
     ]);
 
-    $this->storage->expects($this->exactly(2))
+    $this->storage->expects($this->atLeastOnce())
       ->method('getRevisionTable')
       ->will($this->returnValue('entity_test_revision'));
 
@@ -500,6 +501,7 @@ public function testGetSchemaTranslatable() {
       'columns' => [
         'value' => [
           'type' => 'varchar',
+          'not null' => TRUE,
         ],
       ],
     ]);
@@ -509,6 +511,7 @@ public function testGetSchemaTranslatable() {
         'value' => [
           'type' => 'int',
           'size' => 'tiny',
+          'not null' => TRUE,
         ],
       ],
     ]);
@@ -604,13 +607,13 @@ public function testGetSchemaRevisionableTranslatable() {
       ],
     ]);
 
-    $this->storage->expects($this->exactly(3))
+    $this->storage->expects($this->atLeastOnce())
       ->method('getRevisionTable')
       ->will($this->returnValue('entity_test_revision'));
-    $this->storage->expects($this->once())
+    $this->storage->expects($this->atLeastOnce())
       ->method('getDataTable')
       ->will($this->returnValue('entity_test_field_data'));
-    $this->storage->expects($this->once())
+    $this->storage->expects($this->atLeastOnce())
       ->method('getRevisionDataTable')
       ->will($this->returnValue('entity_test_revision_field_data'));
 
@@ -618,6 +621,7 @@ public function testGetSchemaRevisionableTranslatable() {
       'columns' => [
         'value' => [
           'type' => 'int',
+          'not null' => TRUE,
         ],
       ],
     ]);
@@ -625,6 +629,7 @@ public function testGetSchemaRevisionableTranslatable() {
       'columns' => [
         'value' => [
           'type' => 'varchar',
+          'not null' => TRUE,
         ],
       ],
     ]);
@@ -633,6 +638,7 @@ public function testGetSchemaRevisionableTranslatable() {
         'value' => [
           'type' => 'int',
           'size' => 'tiny',
+          'not null' => TRUE,
         ],
       ],
     ]);
@@ -1403,6 +1409,9 @@ public function setUpStorageDefinition($field_name, array $schema) {
     $this->storageDefinitions[$field_name]->expects($this->any())
       ->method('getColumns')
       ->will($this->returnValue($schema['columns']));
+    $this->storageDefinitions[$field_name]->expects($this->any())
+      ->method('isStorageRequired')
+      ->will($this->returnValue(TRUE));
     // Add property definitions.
     if (!empty($schema['columns'])) {
       $property_definitions = [];
diff --git a/core/tests/Drupal/Tests/Core/Entity/Sql/SqlContentEntityStorageTest.php b/core/tests/Drupal/Tests/Core/Entity/Sql/SqlContentEntityStorageTest.php
index bf3fd46eb6..6c524e958f 100644
--- a/core/tests/Drupal/Tests/Core/Entity/Sql/SqlContentEntityStorageTest.php
+++ b/core/tests/Drupal/Tests/Core/Entity/Sql/SqlContentEntityStorageTest.php
@@ -324,9 +324,6 @@ public function testOnEntityTypeCreate() {
       ->method('getSchema')
       ->will($this->returnValue(['columns' => $columns]));
 
-    $this->entityType->expects($this->once())
-      ->method('getKeys')
-      ->will($this->returnValue(['id' => 'id']));
     $this->entityType->expects($this->any())
       ->method('getKey')
       ->will($this->returnValueMap([
diff --git a/core/tests/Drupal/Tests/Core/Field/TestBaseFieldDefinitionInterface.php b/core/tests/Drupal/Tests/Core/Field/TestBaseFieldDefinitionInterface.php
index 953c90209f..afd19f7d1f 100644
--- a/core/tests/Drupal/Tests/Core/Field/TestBaseFieldDefinitionInterface.php
+++ b/core/tests/Drupal/Tests/Core/Field/TestBaseFieldDefinitionInterface.php
@@ -4,9 +4,10 @@
 
 use Drupal\Core\Field\FieldDefinitionInterface;
 use Drupal\Core\Field\FieldStorageDefinitionInterface;
+use Drupal\Core\Field\RequiredFieldStorageDefinitionInterface;
 
 /**
  * Defines a test interface to mock entity base field definitions.
  */
-interface TestBaseFieldDefinitionInterface extends FieldDefinitionInterface, FieldStorageDefinitionInterface {
+interface TestBaseFieldDefinitionInterface extends FieldDefinitionInterface, FieldStorageDefinitionInterface, RequiredFieldStorageDefinitionInterface {
 }
