diff --git a/core/lib/Drupal/Core/Entity/ContentEntityNullStorage.php b/core/lib/Drupal/Core/Entity/ContentEntityNullStorage.php
index 12aeca3..f31b80e 100644
--- a/core/lib/Drupal/Core/Entity/ContentEntityNullStorage.php
+++ b/core/lib/Drupal/Core/Entity/ContentEntityNullStorage.php
@@ -138,4 +138,11 @@ public function countFieldData($storage_definition, $as_bool = FALSE) {
     return $as_bool ? FALSE : 0;
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function hasData() {
+    return FALSE;
+  }
+
 }
diff --git a/core/lib/Drupal/Core/Entity/FieldableEntityStorageInterface.php b/core/lib/Drupal/Core/Entity/FieldableEntityStorageInterface.php
index aaab687..ed16d33 100644
--- a/core/lib/Drupal/Core/Entity/FieldableEntityStorageInterface.php
+++ b/core/lib/Drupal/Core/Entity/FieldableEntityStorageInterface.php
@@ -107,6 +107,13 @@ public function purgeFieldData(FieldDefinitionInterface $field_definition, $batc
   public function countFieldData($storage_definition, $as_bool = FALSE);
 
   /**
+   * Determines if the storage contains any data.
+   *
+   * @return bool
+   */
+  public function hasData();
+
+  /**
    * Performs final cleanup after all data of a field has been purged.
    *
    * @param \Drupal\Core\Field\FieldStorageDefinitionInterface $storage_definition
diff --git a/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php b/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php
index 61821b0..4b60dad 100644
--- a/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php
+++ b/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php
@@ -1717,6 +1717,17 @@ public function countFieldData($storage_definition, $as_bool = FALSE) {
   }
 
   /**
+   * {@inheritdoc}
+   */
+  public function hasData() {
+    return (bool) $this->database->select($this->getBaseTable(), 'base')
+      ->fields('base')
+      ->countQuery()
+      ->execute()
+      ->fetchField();
+  }
+
+  /**
    * Returns whether the passed field has been already deleted.
    *
    * @param \Drupal\Core\Field\FieldStorageDefinitionInterface $storage_definition
diff --git a/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchema.php b/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchema.php
index de6910f..82eff84 100644
--- a/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchema.php
+++ b/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchema.php
@@ -178,23 +178,16 @@ public function requiresFieldStorageSchemaChanges(FieldStorageDefinitionInterfac
    * {@inheritdoc}
    */
   public function requiresEntityDataMigration(EntityTypeInterface $entity_type, EntityTypeInterface $original) {
-    // If we're updating from NULL storage, then there's no stored data that
-    // requires migration.
-    // @todo Remove in https://www.drupal.org/node/2335879.
     $original_storage_class = $original->getStorageClass();
-    $null_storage_class = 'Drupal\Core\Entity\ContentEntityNullStorage';
-    if ($original_storage_class == $null_storage_class || is_subclass_of($original_storage_class, $null_storage_class)) {
-      return FALSE;
-    }
 
-    return
-      // If the original storage class is different, then there might be
-      // existing entities in that storage even if the new storage's base
-      // table is empty.
-      // @todo Ask the old storage handler rather than assuming:
-      //   https://www.drupal.org/node/2335879.
-      $entity_type->getStorageClass() != $original_storage_class ||
-      !$this->isTableEmpty($this->storage->getBaseTable());
+    // If the original storage class is different, then there might be
+    // existing entities in that storage even if the new storage's base
+    // table is empty.
+    if ($entity_type->getStorageClass() != $original_storage_class) {
+      $original_storage = $original_storage_class::createInstance(\Drupal::getContainer(), $entity_type);
+      return $original_storage->hasData() || $this->storage->hasData();
+    }
+    return $this->storage->hasData();
   }
 
   /**
