diff --git a/core/modules/jsonld/jsonld.info b/core/modules/jsonld/jsonld.info
new file mode 100644
index 0000000..08ec0a5
--- /dev/null
+++ b/core/modules/jsonld/jsonld.info
@@ -0,0 +1,4 @@
+name = JSON-LD
+description = Serializes entities using JSON-LD format.
+core = 8.x
+dependencies[] = entity_test
diff --git a/core/modules/jsonld/jsonld.module b/core/modules/jsonld/jsonld.module
new file mode 100644
index 0000000..0d037f7
--- /dev/null
+++ b/core/modules/jsonld/jsonld.module
@@ -0,0 +1,54 @@
+<?php
+
+/**
+ * @file
+ * Enables entity serialization in JSON-LD.
+ */
+
+use Symfony\Component\Routing\Route;
+use Symfony\Component\Routing\RouteCollection;
+
+/**
+ * Implements hook_serialization_info().
+ */
+function jsonld_serialization_info() {
+  return array(
+    'jsonld_default_normalizer' => array(
+      'type' => 'normalizer',
+      'class' => 'Drupal\jsonld\JsonldNormalizer',
+    ),
+    'jsonld_drupal_normalizer' => array(
+      'type' => 'normalizer',
+      'class' => 'Drupal\jsonld\DrupalJsonldNormalizer',
+    ),
+    'jsonld_default_encoder' => array(
+      'type' => 'encoder',
+      'class' => 'Drupal\jsonld\JsonldEncoder',
+    ),
+    'jsonld_drupal_encoder' => array(
+      'type' => 'encoder',
+      'class' => 'Drupal\jsonld\DrupalJsonldEncoder',
+    ),
+  );
+}
+
+/**
+ * Implements hook_route_info().
+ *
+ * @todo Remove.
+ * Route handling will not be part of serialization modules under normal
+ * circumstances. This is here for testing. Once the REST module has set up
+ * routes, this can be removed.
+ */
+function jsonld_route_info() {
+  $collection = new RouteCollection();
+
+  $entity_test_route = new Route('entity/{entity_type}/{eid}', array(
+    '_controller' => '\Drupal\jsonld\JsonldController::entity_get',
+  ), array(
+    'entity_type' => 'entity-test',
+  ));
+  $collection->add('entity_test_get_json_ld', $entity_test_route);
+
+  return $collection;
+}
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..48edc06
--- /dev/null
+++ b/core/modules/jsonld/lib/Drupal/jsonld/DrupalJsonldEntityWrapper.php
@@ -0,0 +1,28 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\jsonld\DrupalJsonldEntityWrapper.
+ */
+
+namespace Drupal\jsonld;
+
+/**
+ * Provide an interface for DrupalJsonldNormalizer to get required properties.
+ */
+class DrupalJsonldEntityWrapper extends JsonldEntityWrapper {
+
+  /**
+   * Format the 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 = $this->entity->values;
+    unset($properties['id']);
+
+    return $properties;
+  }
+
+}
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/JsonldController.php b/core/modules/jsonld/lib/Drupal/jsonld/JsonldController.php
new file mode 100644
index 0000000..35420ec
--- /dev/null
+++ b/core/modules/jsonld/lib/Drupal/jsonld/JsonldController.php
@@ -0,0 +1,54 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\jsonld\JsonldController
+ *
+ * @todo Serialization modules should not have to register routes or
+ * controllers. Remove this when possible.
+ */
+
+namespace Drupal\jsonld;
+
+use Drupal\Core\Entity\Entity;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Response;
+use Symfony\Component\Serializer\Serializer;
+use Symfony\Component\DependencyInjection\ContainerAwareInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ *
+ */
+class JsonldController implements ContainerAwareInterface {
+
+  /**
+   * The injection container for this object.
+   *
+   * @var \Symfony\Component\DependencyInjection\ContainerInterface
+   */
+  protected $container;
+
+  /**
+   * Injects the service container used by this object.
+   *
+   * @param \Symfony\Component\DependencyInjection\ContainerInterface $container
+   *   The service container this object should use.
+   */
+  public function setContainer(ContainerInterface $container = NULL) {
+    $this->container = $container;
+  }
+
+  public function entity_get($entity_type, $eid) {
+    $entity_type = str_replace('-', '_', $entity_type);
+    $entity = entity_load('entity_test', $eid);
+
+    $serializer = $this->container->get('serializer');
+
+    $jsonld = $serializer->serialize($entity, 'drupal_jsonld');
+
+    $response = new Response($jsonld, 200, array('Content-type' => 'application/json'));
+    return $response;
+  }
+
+}
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..22f202f
--- /dev/null
+++ b/core/modules/jsonld/lib/Drupal/jsonld/JsonldEntityWrapper.php
@@ -0,0 +1,48 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\jsonld\JsonldEntityWrapper.
+ */
+
+namespace Drupal\jsonld;
+
+/**
+ * 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 the properties, format in the JSON-LD array structure and remove
+   * 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/serialization/lib/Drupal/serialization/SerializationBundle.php b/core/modules/serialization/lib/Drupal/serialization/SerializationBundle.php
new file mode 100644
index 0000000..5573a20
--- /dev/null
+++ b/core/modules/serialization/lib/Drupal/serialization/SerializationBundle.php
@@ -0,0 +1,37 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\serialization\SerializationBundle.
+ */
+
+namespace Drupal\serialization;
+
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Component\HttpKernel\Bundle\Bundle;
+use Symfony\Component\Serializer\Serializer;
+
+/**
+ * Bundle class.
+ */
+class SerializationBundle extends Bundle
+{
+  public function build(ContainerBuilder $container) {
+    $plugins = array();
+    $manager = new SerializationPluginManager();
+
+    // Get array of serialization plugins and allow modules to change order.
+    $serialization_info = $manager->getDefinitions();
+    drupal_alter('serialization_info', $serialization_info);
+
+    // Sort the plugins into normalizers and encoders.
+    foreach ($serialization_info as $name => $info) {
+      $plugins[$info['type']][] = $manager->createInstance($name);
+    }
+
+    // Initialize the serializer, passing in all available normalizers and
+    // encoders, and then add it to the DIC.
+    $serializer = new Serializer($plugins['normalizer'], $plugins['encoder']);
+    $container->set('serializer', $serializer);
+  }
+}
diff --git a/core/modules/serialization/lib/Drupal/serialization/SerializationFactory.php b/core/modules/serialization/lib/Drupal/serialization/SerializationFactory.php
new file mode 100644
index 0000000..c5bcad6
--- /dev/null
+++ b/core/modules/serialization/lib/Drupal/serialization/SerializationFactory.php
@@ -0,0 +1,24 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\serialization\SerializationFactory.
+ */
+
+namespace Drupal\serialization;
+
+use Drupal\Component\Plugin\Factory\DefaultFactory;
+
+/**
+ * Factory class for the Serialization plugin type.
+ */
+class SerializationFactory extends DefaultFactory {
+
+  /**
+   * Overrides Drupal\Component\Plugin\Factory\DefaultFactory::createInstance().
+   */
+  public function createInstance($plugin_id, array $configuration) {
+    $plugin_class = $this->getPluginClass($plugin_id);
+    return new $plugin_class();
+  }
+}
diff --git a/core/modules/serialization/lib/Drupal/serialization/SerializationPluginManager.php b/core/modules/serialization/lib/Drupal/serialization/SerializationPluginManager.php
new file mode 100644
index 0000000..6247350
--- /dev/null
+++ b/core/modules/serialization/lib/Drupal/serialization/SerializationPluginManager.php
@@ -0,0 +1,22 @@
+<?php
+
+/**
+ * @file
+ * Defines Drupal\serialization\SerializationPluginManager.
+ */
+
+namespace Drupal\serialization;
+
+use Drupal\Component\Plugin\PluginManagerBase;
+use Drupal\Core\Plugin\Discovery\HookDiscovery;
+use Drupal\Component\Plugin\Factory\DefaultFactory;
+
+/**
+ * Plugin type manager for serializations.
+ */
+class SerializationPluginManager extends PluginManagerBase {
+  public function __construct() {
+    $this->discovery = new HookDiscovery('serialization_info');
+    $this->factory = new SerializationFactory($this);
+  }
+}
diff --git a/core/modules/serialization/serialization.info b/core/modules/serialization/serialization.info
new file mode 100644
index 0000000..221a9bb
--- /dev/null
+++ b/core/modules/serialization/serialization.info
@@ -0,0 +1,3 @@
+name = Serialization
+description = Provides the API for serialization modules to register classes.
+core = 8.x
diff --git a/core/modules/serialization/serialization.module b/core/modules/serialization/serialization.module
new file mode 100644
index 0000000..9de2e1d
--- /dev/null
+++ b/core/modules/serialization/serialization.module
@@ -0,0 +1,6 @@
+<?php
+
+/**
+ * @file
+ * Provides the API for serialization modules to register classes.
+ */
diff --git a/core/modules/system/tests/modules/entity_test/entity_test.module b/core/modules/system/tests/modules/entity_test/entity_test.module
index 46def82..83906b7 100644
--- a/core/modules/system/tests/modules/entity_test/entity_test.module
+++ b/core/modules/system/tests/modules/entity_test/entity_test.module
@@ -18,6 +18,7 @@ function entity_test_entity_info() {
     ),
     'base table' => 'entity_test',
     'data table' => 'entity_test_property_data',
+    'uri callback' => 'entity_test_uri',
     'fieldable' => TRUE,
     'entity keys' => array(
       'id' => 'id',
@@ -137,3 +138,9 @@ function entity_test_form_node_form_alter(&$form, &$form_state, $form_id) {
   $langcode = $form_state['controller']->getFormLangcode($form_state);
   variable_set('entity_form_langcode', $langcode);
 }
+
+function entity_test_uri($entity_test) {
+  return array(
+    'path' => 'entity_test/' . $entity_test->id(),
+  );
+}
