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..0bdd07e
--- /dev/null
+++ b/core/modules/jsonld/lib/Drupal/jsonld/DrupalJsonldEntityWrapper.php
@@ -0,0 +1,41 @@
+<?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');
+
+    // Create language map property structure.
+    foreach ($this->entity->getTranslationLanguages() as $langcode => $language) {
+      foreach ($this->entity->getTranslation($langcode) as $name => $field) {
+        $definition = $this->entity->getPropertyDefinition($name);
+        $langKey = empty($definition['translatable']) ? 'und' : $langcode;
+        if (!$field->isEmpty()) {
+          $properties[$name][$langKey] = $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..61c654a
--- /dev/null
+++ b/core/modules/jsonld/lib/Drupal/jsonld/JsonldNormalizer.php
@@ -0,0 +1,69 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\jsonld\JsonldNormalizer.
+ */
+
+namespace Drupal\jsonld;
+
+use Drupal\Core\Entity\EntityNG;
+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) && ($data instanceof 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..101f6c2
--- /dev/null
+++ b/core/modules/jsonld/lib/Drupal/jsonld/Tests/DrupalJsonldNormalizerTest.php
@@ -0,0 +1,144 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\jsonld\Tests\DrupalJsonldNormalizerTest.
+ */
+
+namespace Drupal\jsonld\Tests;
+
+use Drupal\config\Tests\ConfigEntityTest;
+use Drupal\Core\Language\Language;
+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('entity_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() {
+    // Add German as a language.
+    $language = new Language(array(
+      'langcode' => 'de',
+      'name' => 'Deutsch',
+    ));
+    language_save($language);
+
+    // 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',
+      ),
+    );
+    // Array of translated values.
+    $translationValues = array(
+      'name' => $this->randomName(),
+    );
+
+    $entity = entity_create('entity_test', $values);
+    $entity->save();
+    // Add an English value for name property.
+    $entity->getTranslation('en')->set('name', array(0 => array('value' => $translationValues['name'])));
+
+    $expectedArray = array(
+      '@id' => $this->getEntityId($entity),
+      'uuid' => array(
+        'und' => 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' => $translationValues['name'],
+          ),
+        ),
+      ),
+      'field_test_text' => array(
+        'und' => 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..2ab5261
--- /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('entity_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..229f77b
--- /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', 'entity_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'];
+  }
+
+}
