diff --git a/core/config/schema/core.data_types.schema.yml b/core/config/schema/core.data_types.schema.yml
index 73db361..9972985 100644
--- a/core/config/schema/core.data_types.schema.yml
+++ b/core/config/schema/core.data_types.schema.yml
@@ -580,6 +580,9 @@ field.field_settings.entity_reference:
   type: mapping
   label: 'Entity reference field settings'
   mapping:
+    serialize_embedded_entities:
+      type: boolean
+      label: 'Serialize entity references together with the parent entity'
     handler:
       type: string
       label: 'Reference method'
diff --git a/core/lib/Drupal/Core/Entity/ContentEntityBase.php b/core/lib/Drupal/Core/Entity/ContentEntityBase.php
index 1d69be2..ccb93c1 100644
--- a/core/lib/Drupal/Core/Entity/ContentEntityBase.php
+++ b/core/lib/Drupal/Core/Entity/ContentEntityBase.php
@@ -3,6 +3,7 @@
 namespace Drupal\Core\Entity;
 
 use Drupal\Component\Utility\SafeMarkup;
+use Drupal\Core\Cache\Cache;
 use Drupal\Core\Entity\Plugin\DataType\EntityReference;
 use Drupal\Core\Field\BaseFieldDefinition;
 use Drupal\Core\Language\Language;
@@ -51,6 +52,16 @@
   protected $fieldDefinitions;
 
   /**
+   * Local cache for field definitions filtered by setting.
+   *
+   * @see ContentEntityBase::getFieldDefinitionsFilteredBySetting()
+   *
+   * @var array
+   */
+  protected $fieldDefinitionsFilteredBySetting;
+
+
+  /**
    * Local cache for the available language objects.
    *
    * @var \Drupal\Core\Language\LanguageInterface[]
@@ -149,6 +160,13 @@
   protected $validationRequired = FALSE;
 
   /**
+   * Whether to serialize the complete entity structure.
+   *
+   * @var bool
+   */
+  protected $serializeCompleteEntityStructure = FALSE;
+
+  /**
    * {@inheritdoc}
    */
   public function __construct(array $values, $entity_type, $bundle = FALSE, $translations = array()) {
@@ -407,9 +425,74 @@ protected function clearTranslationCache() {
   }
 
   /**
+   * Gets an array of field definitions of all contained fields filtered by the
+   * given setting and its value.
+   *
+   * @param string $setting
+   *   The name of the setting.
+   * @param string $value
+   *   The value of the setting.
+   *
+   * @return \Drupal\Core\Field\FieldDefinitionInterface[]
+   *   An array of field definitions, keyed by field name.
+   *
+   * @see \Drupal\Core\Entity\EntityFieldManagerInterface::getFieldDefinitions()
+   */
+  protected function getFieldDefinitionsFilteredBySetting($setting, $value) {
+    if (!isset($this->fieldDefinitionsFilteredBySetting[$setting][$value])) {
+      // Initialize the combination of setting and a value in case there is
+      // nothing found to not iterate over the field definitions again.
+      $this->fieldDefinitionsFilteredBySetting[$setting][$value] = [];
+      foreach ($this->getFieldDefinitions() as $name => $definition) {
+        if ($definition->getSetting($setting) == $value) {
+          $this->fieldDefinitionsFilteredBySetting[$setting][$value][$name] = $definition;
+        }
+      }
+    }
+
+    return $this->fieldDefinitionsFilteredBySetting[$setting][$value];
+  }
+
+  /**
    * {@inheritdoc}
    */
   public function __sleep() {
+    if ($this->serializeCompleteEntityStructure) {
+      $langcodes = $this->getTranslationLangcodes();
+      foreach ($this->getFieldDefinitionsFilteredBySetting('serialize_embedded_entities', TRUE) as $name => $definition) {
+        // Initialize not yet initialized fields for which the computed field
+        // values have to be serialized.
+        $iterate_langcodes = $definition->isTranslatable() ? $langcodes : [LanguageInterface::LANGCODE_DEFAULT];
+        foreach ($iterate_langcodes as $langcode) {
+          if (!isset($this->fields[$name][$langcode])) {
+            $this->getTranslatedField($name, $langcode);
+          }
+        }
+
+        // Get the values of instantiated field objects.
+        foreach ($this->fields[$name] as $langcode => $field) {
+          // TODO remove this check after https://www.drupal.org/node/2828133
+          // gets in.
+          if (!$definition->isTranslatable() && ($langcode != LanguageInterface::LANGCODE_DEFAULT)) {
+            continue;
+          }
+
+          // Get the values together with the referenced entities and flag the
+          // referenced entities for deep serialization as well.
+          $this->values[$name][$langcode] = $field->getValue(TRUE);
+          foreach ($this->values[$name][$langcode] as $delta => $values) {
+            // We can assign protected properties of other objects only if they
+            // have the same class as ancestor.
+            $referenced_entities = array_filter($values, function ($val) {return is_object($val) && is_subclass_of($val, ContentEntityBase::class);});
+            foreach ($referenced_entities as $referenced_entity) {
+              $referenced_entity->serializeCompleteEntityStructure = TRUE;
+            }
+          }
+          unset($this->fields[$name]);
+        }
+      }
+    }
+
     // Get the values of instantiated field objects, only serialize the values.
     foreach ($this->fields as $name => $fields) {
       foreach ($fields as $langcode => $field) {
@@ -427,6 +510,24 @@ public function __sleep() {
   /**
    * {@inheritdoc}
    */
+  public function __wakeup() {
+    parent::__wakeup();
+    $this->serializeCompleteEntityStructure = FALSE;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function serializeWithCompleteStructure() {
+    $this->serializeCompleteEntityStructure = TRUE;
+    $serialized = serialize($this);
+    $this->serializeCompleteEntityStructure = FALSE;
+    return $serialized;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   public function id() {
     return $this->getEntityKey('id');
   }
@@ -796,6 +897,7 @@ protected function initializeTranslation($langcode) {
     $translation->enforceIsNew = &$this->enforceIsNew;
     $translation->newRevision = &$this->newRevision;
     $translation->entityKeys = &$this->entityKeys;
+    $translation->serializeCompleteEntityStructure = &$this->serializeCompleteEntityStructure;
     $translation->translatableEntityKeys = &$this->translatableEntityKeys;
     $translation->translationInitialize = FALSE;
     $translation->typedData = NULL;
@@ -883,16 +985,22 @@ public function getTranslationStatus($langcode) {
   /**
    * {@inheritdoc}
    */
-  public function getTranslationLanguages($include_default = TRUE) {
+  public function getTranslationLangcodes($include_default = TRUE) {
     $translations = array_filter($this->translations, function($translation) { return $translation['status']; });
     unset($translations[LanguageInterface::LANGCODE_DEFAULT]);
 
     if ($include_default) {
       $translations[$this->defaultLangcode] = TRUE;
     }
+    return array_keys($translations);
+  }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function getTranslationLanguages($include_default = TRUE) {
     // Now load language objects based upon translation langcodes.
-    return array_intersect_key($this->getLanguages(), $translations);
+    return array_intersect_key($this->getLanguages(), array_flip($this->getTranslationLangcodes($include_default)));
   }
 
   /**
@@ -1066,6 +1174,12 @@ public function __clone() {
       // original reference with one pointing to a copy of it.
       $enforce_is_new = $this->enforceIsNew;
       $this->enforceIsNew = &$enforce_is_new;
+
+      // Ensure the serializeCompleteEntityStructure property is actually
+      // cloned by overwriting the original reference with one pointing to a
+      // copy of it.
+      $serializeCompleteEntityStructure = $this->serializeCompleteEntityStructure;
+      $this->serializeCompleteEntityStructure = &$serializeCompleteEntityStructure;
     }
   }
 
diff --git a/core/lib/Drupal/Core/Entity/ContentEntityInterface.php b/core/lib/Drupal/Core/Entity/ContentEntityInterface.php
index 0c3f04b..5afd451 100644
--- a/core/lib/Drupal/Core/Entity/ContentEntityInterface.php
+++ b/core/lib/Drupal/Core/Entity/ContentEntityInterface.php
@@ -53,4 +53,12 @@ public function setRevisionTranslationAffected($affected);
    */
   public function isRevisionTranslationAffected();
 
+  /**
+   * Returns a deeply serialized entity.
+   *
+   * @return string
+   *   The deeply serialized entity.
+   */
+  public function serializeWithCompleteStructure();
+
 }
diff --git a/core/lib/Drupal/Core/Field/EntityReferenceInlineWidgetBase.php b/core/lib/Drupal/Core/Field/EntityReferenceInlineWidgetBase.php
new file mode 100644
index 0000000..251129c
--- /dev/null
+++ b/core/lib/Drupal/Core/Field/EntityReferenceInlineWidgetBase.php
@@ -0,0 +1,19 @@
+<?php
+
+namespace Drupal\Core\Field;
+
+/**
+ * Base class for 'Entity Reference Inline Widget' plugin implementations.
+ *
+ * @ingroup field_widget
+ */
+abstract class EntityReferenceInlineWidgetBase extends WidgetBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function isApplicable(FieldDefinitionInterface $field_definition) {
+    return (bool) $field_definition->getSetting('serialize_embedded_entities');
+  }
+
+}
diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/EntityReferenceItem.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/EntityReferenceItem.php
index 63bd90d..fd84fa1 100644
--- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/EntityReferenceItem.php
+++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/EntityReferenceItem.php
@@ -53,6 +53,7 @@ public static function defaultStorageSettings() {
    */
   public static function defaultFieldSettings() {
     return array(
+      'serialize_embedded_entities' => FALSE,
       'handler' => 'default',
       'handler_settings' => array(),
     ) + parent::defaultFieldSettings();
@@ -189,7 +190,7 @@ public function setValue($values, $notify = TRUE) {
         // If the entity has been saved and we're trying to set both the
         // target_id and the entity values with a non-null target ID, then the
         // value for target_id should match the ID of the entity value.
-        if (!$this->entity->isNew() && $values['target_id'] !== NULL && ($entity_id !== $values['target_id'])) {
+        if (!$this->entity->isNew() && $values['target_id'] !== NULL && ($entity_id != $values['target_id'])) {
           throw new \InvalidArgumentException('The target id and entity passed to the entity reference item do not match.');
         }
       }
@@ -204,12 +205,12 @@ public function setValue($values, $notify = TRUE) {
   /**
    * {@inheritdoc}
    */
-  public function getValue() {
+  public function getValue($include_computed = FALSE) {
     $values = parent::getValue();
 
     // If there is an unsaved entity, return it as part of the field item values
     // to ensure idempotency of getValue() / setValue().
-    if ($this->hasNewEntity()) {
+    if ($include_computed || $this->hasNewEntity()) {
       $values['entity'] = $this->entity;
     }
     return $values;
@@ -339,6 +340,14 @@ public function fieldSettingsForm(array $form, FormStateInterface $form_state) {
       '#element_validate' => array(array(get_class($this), 'fieldSettingsFormValidate')),
 
     );
+
+    $form['serialize_embedded_entities'] = array(
+      '#type' => 'checkbox',
+      '#title' => $this->t('Serialize entity references together with the parent entity'),
+      '#description' => $this->t('If the field widget to be used for this field is an entity reference inline widget then the setting must be set.'),
+      '#default_value' => $field->getSetting('serialize_embedded_entities'),
+    );
+
     $form['handler'] = array(
       '#type' => 'details',
       '#title' => t('Reference type'),
diff --git a/core/lib/Drupal/Core/TypedData/TranslatableInterface.php b/core/lib/Drupal/Core/TypedData/TranslatableInterface.php
index 5100e6e..5663b16 100644
--- a/core/lib/Drupal/Core/TypedData/TranslatableInterface.php
+++ b/core/lib/Drupal/Core/TypedData/TranslatableInterface.php
@@ -32,6 +32,18 @@ public function isDefaultTranslation();
   public function isNewTranslation();
 
   /**
+   * Returns the language codes of the languages the data is translated to.
+   *
+   * @param bool $include_default
+   *   (optional) Whether the langcode of the default language should be
+   *   included. Defaults to TRUE.
+   *
+   * @return string[]
+   *   An array of language codes.
+   */
+  public function getTranslationLangcodes($include_default = TRUE);
+
+  /**
    * Returns the languages the data is translated to.
    *
    * @param bool $include_default
diff --git a/core/modules/field/field.install b/core/modules/field/field.install
index ecd2b31..6d7c48b 100644
--- a/core/modules/field/field.install
+++ b/core/modules/field/field.install
@@ -6,6 +6,7 @@
  */
 
 use Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem;
+use Drupal\file\Plugin\Field\FieldType\FileItem;
 
 /**
  * Removes the stale 'target_bundle' storage setting on entity_reference fields.
@@ -104,3 +105,39 @@ function field_update_8003() {
     }
   }
 }
+
+/**
+ * @addtogroup updates-8.3.x
+ * @{
+ */
+
+/**
+ * Populate the new 'serialize_embedded_entities' setting for entity reference
+ * fields.
+ */
+function field_update_8300() {
+  $config = \Drupal::configFactory();
+  /** @var \Drupal\Core\Field\FieldTypePluginManager $field_type_manager */
+  $field_type_manager = \Drupal::service('plugin.manager.field.field_type');
+
+  // Iterate over all fields.
+  foreach ($config->listAll('field.field.') as $field_id) {
+    $field = $config->getEditable($field_id);
+    $class = $field_type_manager->getPluginClass($field->get('field_type'));
+
+    // Deal only with entity reference fields and descendants.
+    if ($class == EntityReferenceItem::class || is_subclass_of($class, EntityReferenceItem::class)) {
+      $settings = $field->get('settings');
+
+      if (!isset($settings['serialize_embedded_entities'])) {
+        $settings['serialize_embedded_entities'] = is_subclass_of($class, FileItem::class) ? TRUE : FALSE;
+      }
+
+      $field->set('settings', $settings)->save(TRUE);
+    }
+  }
+}
+
+/**
+ * @} End of "addtogroup updates-8.3.x".
+ */
diff --git a/core/modules/field/tests/src/Kernel/Migrate/d6/MigrateFieldInstanceTest.php b/core/modules/field/tests/src/Kernel/Migrate/d6/MigrateFieldInstanceTest.php
index b3fac3f..951b27b 100644
--- a/core/modules/field/tests/src/Kernel/Migrate/d6/MigrateFieldInstanceTest.php
+++ b/core/modules/field/tests/src/Kernel/Migrate/d6/MigrateFieldInstanceTest.php
@@ -81,6 +81,7 @@ public function testFieldInstanceMigration() {
       'uri_scheme' => 'public',
       'handler' => 'default:file',
       'handler_settings' => array(),
+      'serialize_embedded_entities' => true,
     );
     $field_settings = $field->getSettings();
     ksort($expected);
diff --git a/core/modules/file/config/schema/file.schema.yml b/core/modules/file/config/schema/file.schema.yml
index b9f8918..0b49c88 100644
--- a/core/modules/file/config/schema/file.schema.yml
+++ b/core/modules/file/config/schema/file.schema.yml
@@ -43,6 +43,9 @@ field.value.file:
 base_file_field_field_settings:
   type: mapping
   mapping:
+    serialize_embedded_entities:
+      type: boolean
+      label: 'Serialize entity references together with the parent entity'
     handler:
       type: string
       label: 'Reference method'
diff --git a/core/modules/file/src/Plugin/Field/FieldType/FileItem.php b/core/modules/file/src/Plugin/Field/FieldType/FileItem.php
index 0a9a3b3..1820ea5 100644
--- a/core/modules/file/src/Plugin/Field/FieldType/FileItem.php
+++ b/core/modules/file/src/Plugin/Field/FieldType/FileItem.php
@@ -49,6 +49,7 @@ public static function defaultFieldSettings() {
       'file_directory' => '[date:custom:Y]-[date:custom:m]',
       'max_filesize' => '',
       'description_field' => 0,
+      'serialize_embedded_entities' => TRUE,
     ) + parent::defaultFieldSettings();
   }
 
diff --git a/core/modules/file/src/Plugin/Field/FieldWidget/FileWidget.php b/core/modules/file/src/Plugin/Field/FieldWidget/FileWidget.php
index b2386b4..f508460 100644
--- a/core/modules/file/src/Plugin/Field/FieldWidget/FileWidget.php
+++ b/core/modules/file/src/Plugin/Field/FieldWidget/FileWidget.php
@@ -3,10 +3,10 @@
 namespace Drupal\file\Plugin\Field\FieldWidget;
 
 use Drupal\Component\Utility\NestedArray;
+use Drupal\Core\Field\EntityReferenceInlineWidgetBase;
 use Drupal\Core\Field\FieldDefinitionInterface;
 use Drupal\Core\Field\FieldItemListInterface;
 use Drupal\Core\Field\FieldStorageDefinitionInterface;
-use Drupal\Core\Field\WidgetBase;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
 use Drupal\Core\Render\Element;
@@ -27,7 +27,7 @@
  *   }
  * )
  */
-class FileWidget extends WidgetBase implements ContainerFactoryPluginInterface {
+class FileWidget extends EntityReferenceInlineWidgetBase implements ContainerFactoryPluginInterface {
 
   /**
    * {@inheritdoc}
diff --git a/core/modules/forum/config/optional/field.field.node.forum.taxonomy_forums.yml b/core/modules/forum/config/optional/field.field.node.forum.taxonomy_forums.yml
index f2a30f2..150d28f 100644
--- a/core/modules/forum/config/optional/field.field.node.forum.taxonomy_forums.yml
+++ b/core/modules/forum/config/optional/field.field.node.forum.taxonomy_forums.yml
@@ -16,6 +16,7 @@ translatable: true
 default_value: {  }
 default_value_callback: ''
 settings:
+  serialize_embedded_entities: false
   handler: 'default:taxonomy_term'
   handler_settings:
     target_bundles:
diff --git a/core/profiles/standard/config/install/field.field.node.article.field_image.yml b/core/profiles/standard/config/install/field.field.node.article.field_image.yml
index b4b1c14..b9e8bfc 100644
--- a/core/profiles/standard/config/install/field.field.node.article.field_image.yml
+++ b/core/profiles/standard/config/install/field.field.node.article.field_image.yml
@@ -32,6 +32,7 @@ settings:
     title: ''
     width: null
     height: null
+  serialize_embedded_entities: true
   handler: 'default:file'
   handler_settings: {  }
 field_type: image
diff --git a/core/profiles/standard/config/install/field.field.node.article.field_tags.yml b/core/profiles/standard/config/install/field.field.node.article.field_tags.yml
index 1b9c4cc..fee79a8 100644
--- a/core/profiles/standard/config/install/field.field.node.article.field_tags.yml
+++ b/core/profiles/standard/config/install/field.field.node.article.field_tags.yml
@@ -16,6 +16,7 @@ translatable: true
 default_value: {  }
 default_value_callback: ''
 settings:
+  serialize_embedded_entities: false
   handler: 'default:taxonomy_term'
   handler_settings:
     target_bundles:
diff --git a/core/profiles/standard/config/install/field.field.user.user.user_picture.yml b/core/profiles/standard/config/install/field.field.user.user.user_picture.yml
index b2e61f6..4779b99 100644
--- a/core/profiles/standard/config/install/field.field.user.user.user_picture.yml
+++ b/core/profiles/standard/config/install/field.field.user.user.user_picture.yml
@@ -32,6 +32,7 @@ settings:
     height: null
   alt_field_required: false
   title_field_required: false
+  serialize_embedded_entities: true
   handler: 'default:file'
   handler_settings: {  }
 field_type: image
diff --git a/core/tests/Drupal/KernelTests/Core/Entity/ContentEntitySerializationTest.php b/core/tests/Drupal/KernelTests/Core/Entity/ContentEntitySerializationTest.php
new file mode 100644
index 0000000..efdc981
--- /dev/null
+++ b/core/tests/Drupal/KernelTests/Core/Entity/ContentEntitySerializationTest.php
@@ -0,0 +1,118 @@
+<?php
+
+namespace Drupal\KernelTests\Core\Entity;
+
+use Drupal\field\Entity\FieldConfig;
+use Drupal\field\Entity\FieldStorageConfig;
+
+/**
+ * Tests the serialization of content entities.
+ *
+ * @group Entity
+ */
+class ContentEntitySerializationTest extends EntityKernelTestBase {
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = ['user', 'system', 'field', 'entity_test'];
+
+  /**
+   * The entity type id.
+   *
+   * @var string
+   */
+  protected $entityTypeId;
+
+  /**
+   * The EntityTestMul entity type storage.
+   *
+   * @var \Drupal\Core\Entity\ContentEntityStorageInterface
+   */
+  protected $entityTestMulStorage;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+    $this->entityTypeId = 'entity_test_mul';
+    $this->installEntitySchema($this->entityTypeId);
+    $this->entityTestMulStorage = $this->entityManager->getStorage($this->entityTypeId);
+  }
+
+  /**
+   * Tests regular and deep serialization.
+   */
+  public function testSerialization() {
+    $field_name = 'field_test_entity_reference';
+    // Create the test entity reference field.
+    FieldStorageConfig::create([
+      'field_name' => $field_name,
+      'entity_type' => $this->entityTypeId,
+      'type' => 'entity_reference',
+      'settings' => [
+        'target_type' => $this->entityTypeId,
+      ],
+    ])->save();
+    FieldConfig::create([
+      'entity_type' => $this->entityTypeId,
+      'field_name' => 'field_test_entity_reference',
+      'bundle' => $this->entityTypeId,
+      'translatable' => TRUE,
+    ])->save();
+
+    $this->doTestSerialization(FALSE, $field_name);
+    $this->doTestSerialization(TRUE, $field_name);
+  }
+
+  /**
+   * Tests regular or deep serialization based on the parameter.
+   *
+   * @param bool $deep_serialization
+   *   Whether to test regular or deep serialization.
+   * @param bool $field_name
+   *   The name of the entity reference field.
+   */
+  protected function doTestSerialization($deep_serialization, $field_name) {
+    // Check that the 'target_bundle' setting contains the custom bundle.
+    $field_config = FieldConfig::loadByName($this->entityTypeId, $this->entityTypeId, $field_name);
+    $field_config->setSetting('serialize_embedded_entities', $deep_serialization)
+      ->save();
+
+    $user = $this->createUser();
+    $initial_entity_name = 'test test';
+
+    // Create the test entities.
+    /** @var \Drupal\Core\Entity\ContentEntityInterface $entity_level_zero */
+    $entity_level_zero = $this->entityTestMulStorage->create([
+      'name' => $initial_entity_name,
+      'user_id' => $user->id(),
+      'language' => 'en',
+    ]);
+    $entity_level_zero->save();
+    $entity_level_one = $entity_level_zero->createDuplicate();
+    $entity_level_one->save();
+    $entity_level_two = $entity_level_zero->createDuplicate();
+    $entity_level_two->save();
+
+    $entity_level_zero->$field_name->appendItem($entity_level_one);
+    $entity_level_zero->save();
+    $entity_level_one->$field_name->appendItem($entity_level_two);
+    $entity_level_one->save();
+
+    $entity_level_zero->name = 'entity level zero';
+    $entity_level_zero->$field_name->entity->name = 'entity level one';
+    $entity_level_zero->$field_name->entity->$field_name->entity->name = 'entity level two';
+
+    $this->entityTestMulStorage->resetCache();
+
+    $entity_level_zero = unserialize($entity_level_zero->serializeWithCompleteStructure());
+    $this->assertEquals('entity level zero', $entity_level_zero->label());
+    $this->assertEquals($deep_serialization ? 'entity level one' : $initial_entity_name, $entity_level_zero->$field_name->entity->label());
+    $this->assertEquals($deep_serialization ? 'entity level two' : $initial_entity_name, $entity_level_zero->$field_name->entity->$field_name->entity->label());
+  }
+
+}
