diff --git a/core/lib/Drupal/Core/Entity/ContentEntityBase.php b/core/lib/Drupal/Core/Entity/ContentEntityBase.php
index 1d69be2..0977655 100644
--- a/core/lib/Drupal/Core/Entity/ContentEntityBase.php
+++ b/core/lib/Drupal/Core/Entity/ContentEntityBase.php
@@ -1154,6 +1154,7 @@ 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')) {
@@ -1165,11 +1166,13 @@ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
       $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'))
+        ->setRequired(TRUE)
         ->setDisplayOptions('view', [
           'region' => 'hidden',
         ])
diff --git a/core/lib/Drupal/Core/Entity/EntityFieldManager.php b/core/lib/Drupal/Core/Entity/EntityFieldManager.php
index 5337288..92f47b4 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)
+          ->setRequired(TRUE);
       }
     }
 
diff --git a/core/lib/Drupal/Core/Entity/EntityPublishedTrait.php b/core/lib/Drupal/Core/Entity/EntityPublishedTrait.php
index 871aceb..7b788ec 100644
--- a/core/lib/Drupal/Core/Entity/EntityPublishedTrait.php
+++ b/core/lib/Drupal/Core/Entity/EntityPublishedTrait.php
@@ -37,6 +37,7 @@ public static function publishedBaseFieldDefinitions(EntityTypeInterface $entity
       ->setDescription(new TranslatableMarkup('A boolean indicating the published state.'))
       ->setRevisionable(TRUE)
       ->setTranslatable(TRUE)
+      ->setRequired(TRUE)
       ->setDefaultValue(TRUE)];
   }
 
diff --git a/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchema.php b/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchema.php
index 61da55f..f5140c3 100644
--- a/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchema.php
+++ b/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchema.php
@@ -11,6 +11,7 @@
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Entity\Exception\FieldStorageDefinitionUpdateForbiddenException;
 use Drupal\Core\Entity\Schema\DynamicallyFieldableEntityStorageSchemaInterface;
+use Drupal\Core\Field\BaseFieldDefinition;
 use Drupal\Core\Field\FieldException;
 use Drupal\Core\Field\FieldStorageDefinitionInterface;
 use Drupal\field\FieldStorageConfigInterface;
@@ -1029,11 +1030,7 @@ protected function processRevisionTable(ContentEntityTypeInterface $entity_type,
    * @return array
    *   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;
-  }
+  protected function processDataTable(ContentEntityTypeInterface $entity_type, array &$schema) { }
 
   /**
    * Processes the gathered schema for a base table.
@@ -1046,11 +1043,7 @@ protected function processDataTable(ContentEntityTypeInterface $entity_type, arr
    * @return array
    *   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;
-  }
+  protected function processRevisionDataTable(ContentEntityTypeInterface $entity_type, array &$schema) { }
 
   /**
    * Processes the specified entity key.
@@ -1588,35 +1581,40 @@ protected function getSharedTableFieldSchema(FieldStorageDefinitionInterface $st
     }
 
     $field_name = $storage_definition->getName();
-    $base_table = $this->storage->getBaseTable();
+    $properties = $storage_definition->getPropertyDefinitions();
+
+    $initial_value = [];
+    if ($storage_definition instanceof BaseFieldDefinition) {
+      if (($initial_storage_value = $storage_definition->getInitialValue()) && !empty($initial_storage_value))
+      $initial_value = $initial_value[0];
+    }
 
     // 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. However, even those would break in the
-    // case where a new field is added to a table that contains existing rows.
-    // For now, we only hardcode 'not null' to a couple "entity keys", in order
-    // to keep their indexes optimized.
-    // @todo Revisit once we have support for 'initial' in
-    //   https://www.drupal.org/node/2346019.
-    $not_null_keys = $this->entityType->getKeys();
-    // Label fields are not necessarily required.
-    unset($not_null_keys['label']);
+    // 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])) {
+        $schema['fields'][$schema_field_name]['initial'] = $initial_value[$field_column_name];
+      }
     }
 
     if (!empty($field_schema['indexes'])) {
diff --git a/core/lib/Drupal/Core/Field/BaseFieldDefinition.php b/core/lib/Drupal/Core/Field/BaseFieldDefinition.php
index e28d997..a562fd4 100644
--- a/core/lib/Drupal/Core/Field/BaseFieldDefinition.php
+++ b/core/lib/Drupal/Core/Field/BaseFieldDefinition.php
@@ -12,7 +12,7 @@
 /**
  * A class for defining entity fields.
  */
-class BaseFieldDefinition extends ListDataDefinition implements FieldDefinitionInterface, FieldStorageDefinitionInterface {
+class BaseFieldDefinition extends ListDataDefinition implements FieldDefinitionInterface, FieldStorageDefinitionInterface, RequiredFieldStorageDefinitionInterface {
 
   use UnchangingCacheableDependencyTrait;
 
@@ -503,6 +503,39 @@ public function setDefaultValueCallback($callback) {
     return $this;
   }
 
+  public function getInitialValue() {
+    $value = isset($this->definition['initial_value']) ? $this->definition['initial_value'] : [];
+
+    // Normalize into the "array keyed by delta" format.
+    if (isset($value) && !is_array($value)) {
+      $properties = $this->getPropertyNames();
+      $property = reset($properties);
+      $value = array(
+        array($property => $value),
+      );
+    }
+
+    return $value;
+  }
+
+  public function setInitialValue($value) {
+    if ($value === NULL) {
+      $value = [];
+    }
+    // Unless the value is an empty array, we may need to transform it.
+    if (!is_array($value) || !empty($value)) {
+      if (!is_array($value)) {
+        $value = array(array($this->getMainPropertyName() => $value));
+      }
+      elseif (is_array($value) && !is_numeric(array_keys($value)[0])) {
+        $value = array(0 => $value);
+      }
+    }
+    $this->definition['initial_value'] = $value;
+
+    return $this;
+  }
+
   /**
    * {@inheritdoc}
    */
@@ -723,4 +756,24 @@ public function getConfig($bundle) {
     return BaseFieldOverride::createFromBaseFieldDefinition($this, $bundle);
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function isStorageRequired() {
+    if (isset($this->definition['storage_required'])) {
+      return (bool) $this->definition['storage_required'];
+    }
+
+    // Default to the 'required' property of the base field.
+    return $this->isRequired();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setStorageRequired($required) {
+    $this->definition['storage_required'] = $required;
+    return $this;
+  }
+
 }
diff --git a/core/lib/Drupal/Core/Field/RequiredFieldStorageDefinitionInterface.php b/core/lib/Drupal/Core/Field/RequiredFieldStorageDefinitionInterface.php
new file mode 100644
index 0000000..38a6436
--- /dev/null
+++ b/core/lib/Drupal/Core/Field/RequiredFieldStorageDefinitionInterface.php
@@ -0,0 +1,32 @@
+<?php
+
+namespace Drupal\Core\Field;
+
+/**
+ * Defines an interface for required field storage definitions.
+ */
+interface RequiredFieldStorageDefinitionInterface {
+
+  /**
+   * Returns whether the field storage is required.
+   *
+   * If a field storage is required, NOT NULL constraints will be added
+   * automatically for the required properties of a field type.
+   *
+   * @return bool
+   *   TRUE if the field storage is required, FALSE otherwise.
+   */
+  public function isStorageRequired();
+
+  /**
+   * Sets whether the field storage is required.
+   *
+   * @param bool $required
+   *   Whether the field storage is required.
+   *
+   * @return static
+   *   The object itself for chaining.
+   */
+  public function setStorageRequired($required);
+
+}
diff --git a/core/modules/aggregator/src/Tests/FeedParserTest.php b/core/modules/aggregator/src/Tests/FeedParserTest.php
index 6c4a04d..128ea83 100644
--- a/core/modules/aggregator/src/Tests/FeedParserTest.php
+++ b/core/modules/aggregator/src/Tests/FeedParserTest.php
@@ -85,7 +85,7 @@ public function testHtmlEntitiesSample() {
    */
   public function testRedirectFeed() {
     $redirect_url = Url::fromRoute('aggregator_test.redirect')->setAbsolute()->toString();
-    $feed = Feed::create(array('url' => $redirect_url, 'title' => $this->randomMachineName()));
+    $feed = Feed::create(array('url' => $redirect_url, 'title' => $this->randomMachineName(), 'refresh' => 900));
     $feed->save();
     $feed->refreshItems();
 
@@ -99,7 +99,7 @@ public function testRedirectFeed() {
   public function testInvalidFeed() {
     // Simulate a typo in the URL to force a curl exception.
     $invalid_url = 'http:/www.drupal.org';
-    $feed = Feed::create(array('url' => $invalid_url, 'title' => $this->randomMachineName()));
+    $feed = Feed::create(array('url' => $invalid_url, 'title' => $this->randomMachineName(), 'refresh' => 900));
     $feed->save();
 
     // Update the feed. Use the UI to be able to check the message easily.
diff --git a/core/tests/Drupal/Tests/Core/Entity/BaseFieldDefinitionTest.php b/core/tests/Drupal/Tests/Core/Entity/BaseFieldDefinitionTest.php
index dbd50e7..bb46683 100644
--- a/core/tests/Drupal/Tests/Core/Entity/BaseFieldDefinitionTest.php
+++ b/core/tests/Drupal/Tests/Core/Entity/BaseFieldDefinitionTest.php
@@ -255,6 +255,21 @@ public function testFieldRequired() {
   }
 
   /**
+   * Tests storage required.
+   *
+   * @covers ::isStorageRequired
+   * @covers ::setStorageRequired
+   */
+  public function testFieldStorageRequired() {
+    $definition = BaseFieldDefinition::create($this->fieldType);
+    $this->assertFalse($definition->isStorageRequired());
+    $definition->setStorageRequired(TRUE);
+    $this->assertTrue($definition->isStorageRequired());
+    $definition->setStorageRequired(FALSE);
+    $this->assertFalse($definition->isStorageRequired());
+  }
+
+  /**
    * Tests provider.
    *
    * @covers ::getProvider
