diff --git a/core/modules/jsonld/jsonld.info b/core/modules/jsonld/jsonld.info
new file mode 100644
index 0000000..70d5d40
--- /dev/null
+++ b/core/modules/jsonld/jsonld.info
@@ -0,0 +1,4 @@
+name = JSON-LD
+description = Serializes entities using JSON-LD format.
+package = Core
+core = 8.x
diff --git a/core/modules/jsonld/jsonld.module b/core/modules/jsonld/jsonld.module
new file mode 100644
index 0000000..43410fd
--- /dev/null
+++ b/core/modules/jsonld/jsonld.module
@@ -0,0 +1,20 @@
+<?php
+
+/**
+ * @file
+ * Enables entity serialization in JSON-LD.
+ */
+
+/**
+ * Implements hook_help().
+ */
+function jsonld_help($path, $args) {
+  switch ($path) {
+    case 'admin/help#jsonld':
+      $output = '';
+      $output .= '<p>' . t('The JSON-LD module serializes entities to the <a href="@jsonld_org">JSON-LD</a> data format. To request JSON-LD instead of HTML, a client should add an Accept header to the request. This module will respond with JSON-LD if the Accept header value is one of the following: application/ld_json, which returns an easy-to-use data structure which is compatible with many external schemas, and application/vnd.drupal.ld+json, which is more expressive and is appropriate for content staging.', array(
+        '@jsonld_org' => 'http://json-ld.org/',
+      )) . '</p>';
+      return $output;
+  }
+}
diff --git a/core/modules/jsonld/lib/Drupal/jsonld/DrupalJsonldEncoder.php b/core/modules/jsonld/lib/Drupal/jsonld/DrupalJsonldEncoder.php
new file mode 100644
index 0000000..33dab76
--- /dev/null
+++ b/core/modules/jsonld/lib/Drupal/jsonld/DrupalJsonldEncoder.php
@@ -0,0 +1,27 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\jsonld\DrupalJsonldEncoder.
+ */
+
+namespace Drupal\jsonld;
+
+use Symfony\Component\Serializer\Encoder\EncoderInterface;
+use Symfony\Component\Serializer\Encoder\JsonEncoder;
+
+/**
+ * Encodes JSON-LD data.
+ *
+ * Simply respond to JSON-LD requests using the JSON encoder.
+ */
+class DrupalJsonldEncoder extends JsonldEncoder implements EncoderInterface {
+
+  /**
+   * The format that this Encoder supports.
+   *
+   * @var string
+   */
+  static protected $format = 'drupal_jsonld';
+
+}
diff --git a/core/modules/jsonld/lib/Drupal/jsonld/DrupalJsonldEntityWrapper.php b/core/modules/jsonld/lib/Drupal/jsonld/DrupalJsonldEntityWrapper.php
new file mode 100644
index 0000000..e8601d7
--- /dev/null
+++ b/core/modules/jsonld/lib/Drupal/jsonld/DrupalJsonldEntityWrapper.php
@@ -0,0 +1,57 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\jsonld\DrupalJsonldEntityWrapper.
+ */
+
+namespace Drupal\jsonld;
+
+/**
+ * Provide an interface for DrupalJsonldNormalizer to get required properties.
+ */
+class DrupalJsonldEntityWrapper extends JsonldEntityWrapper {
+
+  /**
+   * Get properties, excluding JSON-LD specific properties.
+   *
+   * Format Entity properties for consumption by other Drupal sites. In
+   * Drupal's vendor specific JSON-LD, fields which correspond to primitives
+   * have an intermediary data structure between the entity and the value.
+   */
+  public function getProperties() {
+    // Properties to skip.
+    $skip = array('id');
+    // Get default language.
+    if ($this->entity->language()->langcode !== 'und') {
+      $defaultLangcode = $this->entity->language();
+    }
+    else {
+      $language = variable_get('language_default');
+      $defaultLangcode = $language['langcode'];
+    }
+
+    // Process all the field values from the default translation.
+    foreach ($this->entity as $name => $field) {
+      $definition = $this->entity->getPropertyDefinition($name);
+      // Add non-translatable values.
+      if ($definition['translatable'] == FALSE) {
+        $properties[$name] = $field->getValue();
+      }
+      // Add values in the default language.
+      else {
+        $properties[$name][$defaultLangcode] = $field->getValue();
+      }
+    }
+    // Add translation values.
+    foreach ($this->entity->getTranslationLanguages(FALSE) as $langcode => $language) {
+      foreach ($this->entity->getTranslation($langcode) as $name => $field) {
+        $properties[$name][$langcode] = $field->getValue();
+      }
+    }
+
+    // Only return properties which are not in the $skip array.
+    return array_diff_key($properties, array_fill_keys($skip, ''));
+  }
+
+}
diff --git a/core/modules/jsonld/lib/Drupal/jsonld/DrupalJsonldNormalizer.php b/core/modules/jsonld/lib/Drupal/jsonld/DrupalJsonldNormalizer.php
new file mode 100644
index 0000000..fec373b
--- /dev/null
+++ b/core/modules/jsonld/lib/Drupal/jsonld/DrupalJsonldNormalizer.php
@@ -0,0 +1,32 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\jsonld\DrupalJsonldNormalizer.
+ */
+
+namespace Drupal\jsonld;
+
+use Symfony\Component\Serializer\Exception\RuntimeException;
+use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
+
+/**
+ * Converts the Drupal entity object structure to JSON-LD array structure.
+ */
+class DrupalJsonldNormalizer extends JsonldNormalizer implements NormalizerInterface {
+
+  /**
+   * The format that this Normalizer supports.
+   *
+   * @var string
+   */
+  static protected $format = 'drupal_jsonld';
+
+  /**
+   * The class to use for the entity wrapper object.
+   *
+   * @var string
+   */
+  protected $entityWrapperClass = 'Drupal\jsonld\DrupalJsonldEntityWrapper';
+
+}
diff --git a/core/modules/jsonld/lib/Drupal/jsonld/JsonldEncoder.php b/core/modules/jsonld/lib/Drupal/jsonld/JsonldEncoder.php
new file mode 100644
index 0000000..cd76a3c
--- /dev/null
+++ b/core/modules/jsonld/lib/Drupal/jsonld/JsonldEncoder.php
@@ -0,0 +1,39 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\jsonld\JsonldEncoder.
+ */
+
+namespace Drupal\jsonld;
+
+use Symfony\Component\Serializer\Encoder\EncoderInterface;
+use Symfony\Component\Serializer\Encoder\JsonEncoder;
+
+/**
+ * Encodes JSON-LD data.
+ *
+ * Simply respond to JSON-LD requests using the JSON encoder.
+ */
+class JsonldEncoder extends JsonEncoder implements EncoderInterface {
+
+  /**
+   * The format that this Encoder supports.
+   *
+   * @var string
+   */
+  static protected $format = 'jsonld';
+
+  /**
+   * Check whether the request is for JSON-LD.
+   *
+   * @param string $format
+   *   The short name of the format returned by ContentNegotiation.
+   *
+   * @return bool
+   *   Returns TRUE if the encoder can handle the request.
+   */
+  public function supportsEncoding($format) {
+    return static::$format === $format;
+  }
+}
diff --git a/core/modules/jsonld/lib/Drupal/jsonld/JsonldEntityWrapper.php b/core/modules/jsonld/lib/Drupal/jsonld/JsonldEntityWrapper.php
new file mode 100644
index 0000000..16cd980
--- /dev/null
+++ b/core/modules/jsonld/lib/Drupal/jsonld/JsonldEntityWrapper.php
@@ -0,0 +1,52 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\jsonld\JsonldEntityWrapper.
+ */
+
+namespace Drupal\jsonld;
+
+use Drupal\Core\Entity\EntityNG;
+
+/**
+ * Provide an interface for JsonldNormalizer to get required properties.
+ */
+class JsonldEntityWrapper {
+
+  /**
+   * The entity that this object wraps.
+   *
+   * @var Drupal\Core\Entity\EntityNG
+   */
+  protected $entity;
+
+  /**
+   * Constructor.
+   *
+   * @param string $entity
+   *   The Entity API entity
+   */
+  public function __construct(EntityNG $entity) {
+    $this->entity = $entity;
+  }
+
+  /**
+   * Get the Entity's URI for the @id attribute.
+   */
+  public function getId() {
+    $uri_info = $this->entity->uri();
+    return url($uri_info['path'], array('absolute' => TRUE));
+  }
+
+  /**
+   * Get properties, excluding JSON-LD specific properties.
+   *
+   * Formats Entity properties in the JSON-LD array structure and removes
+   * unwanted values.
+   */
+  public function getProperties() {
+    // @todo Add property handling based on http://drupal.org/node/1813328.
+    return array();
+  }
+}
diff --git a/core/modules/jsonld/lib/Drupal/jsonld/JsonldNormalizer.php b/core/modules/jsonld/lib/Drupal/jsonld/JsonldNormalizer.php
new file mode 100644
index 0000000..6bd6db9
--- /dev/null
+++ b/core/modules/jsonld/lib/Drupal/jsonld/JsonldNormalizer.php
@@ -0,0 +1,68 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\jsonld\JsonldNormalizer.
+ */
+
+namespace Drupal\jsonld;
+
+use Symfony\Component\Serializer\Exception\RuntimeException;
+use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
+
+/**
+ * Converts the Drupal entity object structure to JSON-LD array structure.
+ */
+class JsonldNormalizer implements NormalizerInterface {
+
+  /**
+   * The format that this Normalizer supports.
+   *
+   * @var string
+   */
+  static protected $format = 'jsonld';
+
+  /**
+   * The class to use for the entity wrapper object.
+   *
+   * @var string
+   */
+  protected $entityWrapperClass = 'Drupal\jsonld\JsonldEntityWrapper';
+
+  /**
+   * Normalizes an object into a set of arrays/scalars.
+   *
+   * @param object $object
+   *   Object to normalize.
+   * @param string $format
+   *   Format the normalization result will be encoded as.
+   *
+   * @return array
+   *   An array containing the properties of the entity and JSON-LD specific
+   *   attributes such as '@context' and '@id'.
+   */
+  public function normalize($object, $format = NULL) {
+    $entityWrapper = new $this->entityWrapperClass($object);
+
+    $attributes = $entityWrapper->getProperties();
+    $attributes = array('@id' => $entityWrapper->getId()) + $attributes;
+    return $attributes;
+  }
+
+  /**
+   * Checks whether the data and format are supported by this normalizer.
+   *
+   * @param mixed  $data
+   *   Data to normalize.
+   * @param string $format
+   *   Format the normalization result will be encoded as.
+   *
+   * @return bool
+   *   Returns TRUE if the normalizer can handle the request.
+   */
+  public function supportsNormalization($data, $format = NULL) {
+    // If this is an Entity object and the request is for JSON-LD.
+    return is_object($data) && is_subclass_of($data, 'Drupal\Core\Entity\EntityNG') && static::$format === $format;
+  }
+
+}
diff --git a/core/modules/jsonld/lib/Drupal/jsonld/Tests/DrupalJsonldNormalizerTest.php b/core/modules/jsonld/lib/Drupal/jsonld/Tests/DrupalJsonldNormalizerTest.php
new file mode 100644
index 0000000..08e3844
--- /dev/null
+++ b/core/modules/jsonld/lib/Drupal/jsonld/Tests/DrupalJsonldNormalizerTest.php
@@ -0,0 +1,132 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\jsonld\Tests\DrupalJsonldNormalizerTest.
+ */
+
+namespace Drupal\jsonld\Tests;
+
+use Drupal\config\Tests\ConfigEntityTest;
+use Drupal\jsonld\DrupalJsonldNormalizer;
+use Drupal\jsonld\Tests\JsonldNormalizerTestBase;
+
+/**
+ * Test the vendor specific JSON-LD normalizer.
+ */
+class DrupalJsonldNormalizerTest extends JsonldNormalizerTestBase {
+  /**
+   * The normalizer to be tested.
+   */
+  protected $normalizer;
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Drupal JSON-LD Normalizer',
+      'description' => "Test Drupal's vendor specific JSON-LD normalizer.",
+      'group' => 'JSON-LD',
+    );
+  }
+
+  /**
+   * Add the normalizer to be tested.
+   */
+  function setUp() {
+    parent::setUp();
+
+    $this->normalizer = new DrupalJsonldNormalizer();
+  }
+
+  /**
+   * Tests the supportsNormalization function.
+   */
+  public function testSupportsNormalization() {
+    $function = 'DrupalJsonldNormalizer::supportsNormlization';
+    $supportedFormat = 'drupal_jsonld';
+    $unsupportedFormat = 'jsonld';
+    $supportedEntity = entity_create('jsonld_test', array());
+    $unsupportedEntity = new ConfigEntityTest();
+
+    // Supported entity, supported format.
+    $this->assertTrue($this->normalizer->supportsNormalization($supportedEntity, $supportedFormat), "$function returns TRUE for supported format.");
+    // Supported entity, unsupported format.
+    $this->assertFalse($this->normalizer->supportsNormalization($supportedEntity, $unsupportedFormat), "$function returns FALSE for unsupported format.");
+    // Unsupported entity, supported format.
+    $this->assertFalse($this->normalizer->supportsNormalization($unsupportedEntity, $supportedFormat), "$function returns FALSE for unsupported entity type.");
+  }
+
+  /**
+   * Tests the normalize function.
+   */
+  public function testNormalize() {
+    // Create a German entity.
+    $values = array(
+      'langcode' => 'de',
+      'name' => $this->randomName(),
+      'user_id' => $GLOBALS['user']->uid,
+      'field_test_text' => array(
+        'value' => $this->randomName(),
+        'format' => 'full_html',
+      ),
+    );
+
+    $langSpecificValues = array(
+      'name' => $this->randomName(),
+    );
+
+    $entity = entity_create('jsonld_test', $values);
+    $entity->save();
+    // Add an English value for name property.
+    $entity->getTranslation('en')->set('name', array(0 => array('value' => $langSpecificValues['name'])));
+
+    $expectedArray = array(
+      '@id' => $this->getEntityId($entity),
+      'uuid' => array(
+        array(
+          'value' => $entity->uuid(),
+        ),
+      ),
+      'user_id' => array(
+        'de' => array(
+          array(
+            'value' => 1,
+          ),
+        ),
+      ),
+      'name' => array(
+        'de' => array(
+          array(
+            'value' => $values['name'],
+          ),
+        ),
+        'en' => array(
+          array(
+            'value' => $langSpecificValues['name'],
+          ),
+        ),
+      ),
+      'field_test_text' => array(
+        array(
+          'value' => $values['field_test_text']['value'],
+          'format' => $values['field_test_text']['format'],
+        ),
+      ),
+    );
+
+    $normalized = $this->normalizer->normalize($entity);
+    // Test ordering. The @context and @id properties should always be first.
+    $keys = array_keys($normalized);
+    $this->assertEqual($keys[0], '@id', '@id and @context attributes placed correctly.');
+    // Test @id value.
+    $this->assertEqual($normalized['@id'], $expectedArray['@id'], '@id uses correct value.');
+    // Test non-translatable field.
+    $this->assertEqual($normalized['uuid'], $expectedArray['uuid'], 'Non-translatable fields are nested correctly.');
+    // Test single-language translatable.
+    $this->assertEqual($normalized['user_id'], $expectedArray['user_id'], 'Translatable field with single language value is nested correctly.');
+    // Test multi-language translatable.
+    $this->assertEqual($normalized['name'], $expectedArray['name'], 'Translatable field with multiple language values is nested correctly.');
+    // Test multi-property untranslatable field.
+    $this->assertEqual($normalized['field_test_text'], $expectedArray['field_test_text'], 'Field with properties is nested correctly.');
+  }
+
+}
diff --git a/core/modules/jsonld/lib/Drupal/jsonld/Tests/JsonldNormalizerTest.php b/core/modules/jsonld/lib/Drupal/jsonld/Tests/JsonldNormalizerTest.php
new file mode 100644
index 0000000..6d3a2fc
--- /dev/null
+++ b/core/modules/jsonld/lib/Drupal/jsonld/Tests/JsonldNormalizerTest.php
@@ -0,0 +1,58 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\jsonld\Tests\JsonldNormalizerTest.
+ */
+
+namespace Drupal\jsonld\Tests;
+
+use Drupal\config\Tests\ConfigEntityTest;
+use Drupal\jsonld\JsonldNormalizer;
+use Drupal\jsonld\Tests\JsonldNormalizerTestBase;
+
+/**
+ * Test the default JSON-LD normalizer.
+ */
+class JsonldNormalizerTest extends JsonldNormalizerTestBase {
+  /**
+   * The normalizer to be tested.
+   */
+  protected $normalizer;
+
+  public static function getInfo() {
+    return array(
+      'name' => 'JSON-LD Normalizer',
+      'description' => "Test the JSON-LD normalizer.",
+      'group' => 'JSON-LD',
+    );
+  }
+
+  /**
+   * Add the normalizer to be tested.
+   */
+  function setUp() {
+    parent::setUp();
+
+    $this->normalizer = new JsonldNormalizer();
+  }
+
+  /**
+   * Tests the supportsNormalization function.
+   */
+  public function testSupportsNormalization() {
+    $function = 'JsonldNormalizer::supportsNormlization';
+    $supportedFormat = 'jsonld';
+    $unsupportedFormat = 'drupal_jsonld';
+    $supportedEntity = entity_create('jsonld_test', array());
+    $unsupportedEntity = new ConfigEntityTest();
+
+    // Supported entity, supported format.
+    $this->assertTrue($this->normalizer->supportsNormalization($supportedEntity, $supportedFormat), "$function returns TRUE for supported format.");
+    // Supported entity, unsupported format.
+    $this->assertFalse($this->normalizer->supportsNormalization($supportedEntity, $unsupportedFormat), "$function returns FALSE for unsupported format.");
+    // Unsupported entity, supported format.
+    $this->assertFalse($this->normalizer->supportsNormalization($unsupportedEntity, $supportedFormat), "$function returns FALSE for unsupported entity type.");
+  }
+
+}
diff --git a/core/modules/jsonld/lib/Drupal/jsonld/Tests/JsonldNormalizerTestBase.php b/core/modules/jsonld/lib/Drupal/jsonld/Tests/JsonldNormalizerTestBase.php
new file mode 100644
index 0000000..dd3ea0d
--- /dev/null
+++ b/core/modules/jsonld/lib/Drupal/jsonld/Tests/JsonldNormalizerTestBase.php
@@ -0,0 +1,39 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\jsonld\Tests\JsonldTestBase.
+ */
+
+namespace Drupal\jsonld\Tests;
+
+use Drupal\simpletest\WebTestBase;
+use Drupal\config\Tests\ConfigEntityTest;
+
+/**
+ * Parent class for JSON-LD tests.
+ */
+abstract class JsonldNormalizerTestBase extends WebTestBase {
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = array('language', 'jsonld_test');
+
+  /**
+   * Get the Entity ID.
+   *
+   * @param Drupal\Core\Entity\EntityNG $entity
+   *   Entity to get URI for.
+   *
+   * @return string
+   *   Return the entity URI.
+   */
+  protected function getEntityId($entity) {
+    global $base_url;
+    $uriInfo = $entity->uri();
+    return $base_url . '/' . $uriInfo['path'];
+  }
+
+}
diff --git a/core/modules/jsonld/tests/modules/jsonld_test/jsonld_test.info b/core/modules/jsonld/tests/modules/jsonld_test/jsonld_test.info
new file mode 100644
index 0000000..7436c09
--- /dev/null
+++ b/core/modules/jsonld/tests/modules/jsonld_test/jsonld_test.info
@@ -0,0 +1,6 @@
+name = JSON-LD test module
+description = Provides entity types for testing JSON-LD.
+package = Testing
+core = 8.x
+dependencies[] = field
+hidden = TRUE
diff --git a/core/modules/jsonld/tests/modules/jsonld_test/jsonld_test.install b/core/modules/jsonld/tests/modules/jsonld_test/jsonld_test.install
new file mode 100644
index 0000000..9496d0e
--- /dev/null
+++ b/core/modules/jsonld/tests/modules/jsonld_test/jsonld_test.install
@@ -0,0 +1,112 @@
+<?php
+
+/**
+ * @file
+ * Install, update and uninstall functions for the jsonld_test module.
+ */
+
+/**
+ * Implements hook_install().
+ */
+function jsonld_test_install() {
+  // Auto-create a field for testing.
+  $field = array(
+    'field_name' => 'field_test_text',
+    'type' => 'text',
+    'cardinality' => 1,
+    'translatable' => FALSE,
+  );
+  field_create_field($field);
+
+  $instance = array(
+    'entity_type' => 'jsonld_test',
+    'field_name' => 'field_test_text',
+    'bundle' => 'jsonld_test',
+    'label' => 'Test text-field',
+    'widget' => array(
+      'type' => 'text_textfield',
+      'weight' => 0,
+    ),
+  );
+  field_create_instance($instance);
+}
+
+/**
+ * Implements hook_schema().
+ */
+function jsonld_test_schema() {
+  $schema['jsonld_test'] = array(
+    'description' => 'Stores jsonld_test items.',
+    'fields' => array(
+      'id' => array(
+        'type' => 'serial',
+        'not null' => TRUE,
+        'description' => 'Primary Key: Unique entity-test item ID.',
+      ),
+      'uuid' => array(
+        'description' => 'Unique Key: Universally unique identifier for this entity.',
+        'type' => 'varchar',
+        'length' => 128,
+        'not null' => FALSE,
+      ),
+      'langcode' => array(
+        'description' => 'The {language}.langcode of the original variant of this test entity.',
+        'type' => 'varchar',
+        'length' => 12,
+        'not null' => TRUE,
+        'default' => '',
+      ),
+    ),
+    'primary key' => array('id'),
+    'unique keys' => array(
+      'uuid' => array('uuid'),
+    ),
+  );
+  $schema['jsonld_test_property_data'] = array(
+    'description' => 'Stores jsonld_test item properties.',
+    'fields' => array(
+      'id' => array(
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'description' => 'The {jsonld_test}.id of the test entity.',
+      ),
+      'langcode' => array(
+        'description' => 'The {language}.langcode of this variant of this test entity.',
+        'type' => 'varchar',
+        'length' => 12,
+        'not null' => TRUE,
+        'default' => '',
+      ),
+      'default_langcode' => array(
+        'description' => 'Boolean indicating whether the current variant is in the original entity language.',
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 1,
+      ),
+      'name' => array(
+        'description' => 'The name of the test entity.',
+        'type' => 'varchar',
+        'length' => 32,
+        'not null' => TRUE,
+        'default' => '',
+      ),
+      'user_id' => array(
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => FALSE,
+        'default' => NULL,
+        'description' => "The {users}.uid of the associated user.",
+      ),
+    ),
+    'indexes' => array(
+      'user_id' => array('user_id'),
+    ),
+    'foreign keys' => array(
+      'user_id' => array('users' => 'uid'),
+      'id' => array('jsonld_test' => 'id'),
+    ),
+    'primary key' => array('id', 'langcode'),
+  );
+  return $schema;
+}
diff --git a/core/modules/jsonld/tests/modules/jsonld_test/jsonld_test.module b/core/modules/jsonld/tests/modules/jsonld_test/jsonld_test.module
new file mode 100644
index 0000000..7f9997b
--- /dev/null
+++ b/core/modules/jsonld/tests/modules/jsonld_test/jsonld_test.module
@@ -0,0 +1,25 @@
+<?php
+
+/**
+ * @file
+ * Test module for the entity API providing an entity type for testing.
+ */
+
+/**
+ * Implements hook_entity_info().
+ */
+function jsonld_test_entity_info() {
+  $items['jsonld_test'] = array(
+    'label' => t('Test entity'),
+    'entity class' => 'Drupal\jsonld_test\JsonldTest',
+    'controller class' => 'Drupal\jsonld_test\JsonldTestStorageController',
+    'base table' => 'jsonld_test',
+    'data table' => 'jsonld_test_property_data',
+    'fieldable' => TRUE,
+    'entity keys' => array(
+      'id' => 'id',
+      'uuid' => 'uuid',
+    ),
+  );
+  return $items;
+}
diff --git a/core/modules/jsonld/tests/modules/jsonld_test/lib/Drupal/jsonld_test/JsonldTest.php b/core/modules/jsonld/tests/modules/jsonld_test/lib/Drupal/jsonld_test/JsonldTest.php
new file mode 100644
index 0000000..3155b8a
--- /dev/null
+++ b/core/modules/jsonld/tests/modules/jsonld_test/lib/Drupal/jsonld_test/JsonldTest.php
@@ -0,0 +1,58 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\jsonld_test\JsonldTest.
+ */
+
+namespace Drupal\jsonld_test;
+
+use Drupal\Core\Entity\EntityNG;
+
+/**
+ * Defines the test entity class.
+ */
+class JsonldTest extends EntityNG {
+
+  /**
+   * The entity ID.
+   *
+   * @var \Drupal\Core\Entity\Field\FieldInterface
+   */
+  public $id;
+
+  /**
+   * The entity UUID.
+   *
+   * @var \Drupal\Core\Entity\Field\FieldInterface
+   */
+  public $uuid;
+
+  /**
+   * The name of the test entity.
+   *
+   * @var \Drupal\Core\Entity\Field\FieldInterface
+   */
+  public $name;
+
+  /**
+   * The associated user.
+   *
+   * @var \Drupal\Core\Entity\Field\FieldInterface
+   */
+  public $user_id;
+
+  /**
+   * Overrides Entity::__construct().
+   */
+  public function __construct(array $values, $entity_type) {
+    parent::__construct($values, $entity_type);
+
+    // We unset all defined properties, so magic getters apply.
+    unset($this->id);
+    unset($this->langcode);
+    unset($this->uuid);
+    unset($this->name);
+    unset($this->user_id);
+  }
+}
diff --git a/core/modules/jsonld/tests/modules/jsonld_test/lib/Drupal/jsonld_test/JsonldTestStorageController.php b/core/modules/jsonld/tests/modules/jsonld_test/lib/Drupal/jsonld_test/JsonldTestStorageController.php
new file mode 100644
index 0000000..016ca69
--- /dev/null
+++ b/core/modules/jsonld/tests/modules/jsonld_test/lib/Drupal/jsonld_test/JsonldTestStorageController.php
@@ -0,0 +1,55 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\jsonld_test\JsonldTestStorageController.
+ */
+
+namespace Drupal\jsonld_test;
+
+use Drupal\Core\Entity\DatabaseStorageControllerNG;
+
+/**
+ * Defines the controller class for the test entity.
+ *
+ * This extends the Drupal\Core\Entity\DatabaseStorageController class, adding
+ * required special handling for test entities.
+ */
+class JsonldTestStorageController extends DatabaseStorageControllerNG {
+
+  /**
+   * Implements \Drupal\Core\Entity\DataBaseStorageControllerNG::baseFieldDefinitions().
+   */
+  public function baseFieldDefinitions() {
+    $fields['id'] = array(
+      'label' => t('ID'),
+      'description' => t('The ID of the test entity.'),
+      'type' => 'integer_field',
+      'read-only' => TRUE,
+    );
+    $fields['uuid'] = array(
+      'label' => t('UUID'),
+      'description' => t('The UUID of the test entity.'),
+      'type' => 'string_field',
+    );
+    $fields['langcode'] = array(
+      'label' => t('Language code'),
+      'description' => t('The language code of the test entity.'),
+      'type' => 'language_field',
+    );
+    $fields['name'] = array(
+      'label' => t('Name'),
+      'description' => t('The name of the test entity.'),
+      'type' => 'string_field',
+      'translatable' => TRUE,
+    );
+    $fields['user_id'] = array(
+      'label' => t('User ID'),
+      'description' => t('The ID of the associated user.'),
+      'type' => 'entityreference_field',
+      'settings' => array('entity type' => 'user'),
+      'translatable' => TRUE,
+    );
+    return $fields;
+  }
+}
