diff --git a/rdf_example/config/field.field.node.recipe_photo.yml b/rdf_example/config/field.field.node.recipe_photo.yml
new file mode 100644
index 0000000..8f21cf2
--- /dev/null
+++ b/rdf_example/config/field.field.node.recipe_photo.yml
@@ -0,0 +1,28 @@
+id: node.recipe_photo
+uuid: cc757d7b-92d1-4620-9103-3e621052c21f
+status: true
+langcode: en
+name: recipe_photo
+entity_type: node
+type: image
+settings:
+  uri_scheme: public
+  default_image:
+    fid: null
+    alt: ''
+    title: ''
+    width: null
+    height: null
+  target_type: file
+  display_field: 0
+  display_default: 0
+  target_bundle: null
+module: image
+locked: false
+cardinality: 1
+translatable: false
+indexes: {  }
+dependencies:
+  module:
+    - image
+    - node
diff --git a/rdf_example/config/field.field.node.recipe_summary.yml b/rdf_example/config/field.field.node.recipe_summary.yml
new file mode 100644
index 0000000..f9cfcb5
--- /dev/null
+++ b/rdf_example/config/field.field.node.recipe_summary.yml
@@ -0,0 +1,17 @@
+id: node.recipe_summary
+uuid: 32224012-99be-4288-a700-bc2209fe6272
+status: true
+langcode: en
+name: recipe_summary
+entity_type: node
+type: text_long
+settings: {  }
+module: text
+locked: false
+cardinality: 1
+translatable: false
+indexes: {  }
+dependencies:
+  module:
+    - node
+    - text
diff --git a/rdf_example/config/field.instance.node.recipe.recipe_photo.yml b/rdf_example/config/field.instance.node.recipe.recipe_photo.yml
new file mode 100644
index 0000000..77e3032
--- /dev/null
+++ b/rdf_example/config/field.instance.node.recipe.recipe_photo.yml
@@ -0,0 +1,35 @@
+id: node.recipe.recipe_photo
+uuid: 1055e85a-590e-4e2f-ab19-2593bf84df28
+status: true
+langcode: en
+field_uuid: cc757d7b-92d1-4620-9103-3e621052c21f
+field_name: recipe_photo
+entity_type: node
+bundle: recipe
+label: Photo
+description: 'Photo of the prepared dish.'
+required: false
+default_value: {  }
+default_value_function: ''
+settings:
+  file_directory: ''
+  file_extensions: 'png gif jpg jpeg'
+  max_filesize: ''
+  max_resolution: ''
+  min_resolution: ''
+  alt_field: false
+  alt_field_required: false
+  title_field: false
+  title_field_required: false
+  default_image:
+    fid: null
+    alt: ''
+    title: ''
+    width: null
+    height: null
+  handler: default
+dependencies:
+  entity:
+    - field.field.node.recipe_photo
+    - node.type.recipe
+field_type: image
diff --git a/rdf_example/config/field.instance.node.recipe.recipe_summary.yml b/rdf_example/config/field.instance.node.recipe.recipe_summary.yml
new file mode 100644
index 0000000..2b43577
--- /dev/null
+++ b/rdf_example/config/field.instance.node.recipe.recipe_summary.yml
@@ -0,0 +1,20 @@
+id: node.recipe.recipe_summary
+uuid: a11ade81-1385-4f8d-bb51-812258eb3264
+status: true
+langcode: en
+field_uuid: 32224012-99be-4288-a700-bc2209fe6272
+field_name: recipe_summary
+entity_type: node
+bundle: recipe
+label: Summary
+description: 'Short summary describing the dish.'
+required: false
+default_value: {  }
+default_value_function: ''
+settings:
+  text_processing: '0'
+dependencies:
+  entity:
+    - field.field.node.recipe_summary
+    - node.type.recipe
+field_type: text_long
diff --git a/rdf_example/config/node.type.recipe.yml b/rdf_example/config/node.type.recipe.yml
new file mode 100644
index 0000000..b70743e
--- /dev/null
+++ b/rdf_example/config/node.type.recipe.yml
@@ -0,0 +1,18 @@
+type: recipe
+name: 'Recipe'
+description: 'The recipe node is defined to demonstrate RDF mapping.'
+help: ''
+has_title: true
+title_label: Title
+settings:
+  node:
+    options:
+      status: true
+      promote: true
+      sticky: false
+      revision: false
+    preview: 1
+    submitted: true
+status: true
+uuid: b419ba49-f1c6-4cfc-9252-82f59c491eae
+dependencies: {  }
diff --git a/rdf_example/config/rdf.mapping.node.recipe.yml b/rdf_example/config/rdf.mapping.node.recipe.yml
new file mode 100644
index 0000000..aa35a75
--- /dev/null
+++ b/rdf_example/config/rdf.mapping.node.recipe.yml
@@ -0,0 +1,23 @@
+id: node.recipe
+targetEntityType: node
+bundle: recipe
+types:
+  - 'v:Recipe'
+fieldMappings:
+  title:
+    properties:
+      - 'dc:title'
+      - 'v:name'
+  recipe_summary:
+    properties:
+      - 'v:summary'
+  recipe_photo:
+    properties:
+      - 'v:photo'
+    mapping_type: 'rel'
+dependencies:
+  entity:
+    - node.type.recipe
+  module:
+    - rdf_example
+    - node
diff --git a/rdf_example/lib/Drupal/rdf_example/Controller/RDFExampleController.php b/rdf_example/lib/Drupal/rdf_example/Controller/RDFExampleController.php
new file mode 100644
index 0000000..8a0c150
--- /dev/null
+++ b/rdf_example/lib/Drupal/rdf_example/Controller/RDFExampleController.php
@@ -0,0 +1,27 @@
+<?php
+/**
+ * @file
+ * Contains \Drupal\rdf_example\Controller\RDFExampleController.
+ */
+
+namespace Drupal\rdf_example\Controller;
+
+/**
+ * Controller routines for RDF example routes.
+ */
+class RDFExampleController {
+
+  /**
+   * Provide a basic description of this module's functionality.
+   */
+  public function description() {
+    $build = array(
+      '#markup' => t("The RDF Example module supplies a custom node type with
+      prepared RDF mappings. In addition, the RDFExampleModifyMappingsTest test
+      case illustrates the use of the Configuration API to alter a node bundle's
+      existing mappings"),
+    );
+
+    return $build;
+  }
+}
diff --git a/rdf_example/lib/Drupal/rdf_example/Tests/RDFExampleMappingsTest.php b/rdf_example/lib/Drupal/rdf_example/Tests/RDFExampleMappingsTest.php
new file mode 100644
index 0000000..357e359
--- /dev/null
+++ b/rdf_example/lib/Drupal/rdf_example/Tests/RDFExampleMappingsTest.php
@@ -0,0 +1,77 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\rdf_example\Tests\RDFExampleMappingsTest
+ */
+
+namespace Drupal\rdf_example\Tests;
+
+use Drupal\simpletest\WebTestBase;
+
+/**
+ * Tests for the rdf_example module.
+ */
+class RDFExampleMappingsTest extends WebTestBase {
+
+  public static $modules = array('text', 'image', 'node', 'rdf', 'rdf_example');
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'RDFa markup',
+      'description' => 'Test RDFa markup generation.',
+      'group' => 'Examples',
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setUp() {
+    parent::setUp();
+    $this->base_uri = \Drupal::url('<front>', array(), array('absolute' => TRUE));
+  }
+
+  /**
+   * Test that RDFa attributes are correctly inserted into node page markup.
+   */
+  public function testAttributesInMarkup() {
+    $node = $this->drupalCreateNode(array('type' => 'recipe'));
+    $url = $node->url('canonical', array('absolute' => TRUE));
+
+    $parser = new \EasyRdf_Parser_Rdfa();
+    $graph = new \EasyRdf_Graph();
+
+    $parser->parse($graph, $this->drupalGet($url), 'rdfa', $this->base_uri);
+
+    // Test that the type is applied.
+    $this->assertTrue(
+      in_array('v:Recipe', $graph->types($this->url)),
+      'RDF type is present on recipe node.'
+    );
+
+    // Test that the node title is mapped to dc:title and v:name.
+    $node_title = $node->getTitle();
+    $expected_title_value = array(
+      'type' => 'literal',
+      'value' => $node_title,
+      'lang' => 'en',
+    );
+
+    $dc_title = 'http://purl.org/dc/terms/title';
+    $this->assertTrue(
+      $graph->hasProperty($this->url, $dc_title, $expected_title_value),
+      'Node title found with dc:title property.'
+    );
+
+    $v_name = 'http://rdf.data-vocabulary.org/#name';
+    $this->assertTrue(
+      $graph->hasProperty($this->url, $v_name, $expected_title_value),
+      'Node title found with v:name property.'
+    );
+
+  }
+}
diff --git a/rdf_example/lib/Drupal/rdf_example/Tests/RDFExampleModifyMappingsTest.php b/rdf_example/lib/Drupal/rdf_example/Tests/RDFExampleModifyMappingsTest.php
new file mode 100644
index 0000000..23a8d02
--- /dev/null
+++ b/rdf_example/lib/Drupal/rdf_example/Tests/RDFExampleModifyMappingsTest.php
@@ -0,0 +1,114 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\rdf_example\Tests\RDFExampleModifyMappingsTest
+ */
+
+namespace Drupal\rdf_example\Tests;
+
+use Drupal\simpletest\WebTestBase;
+
+class RDFExampleModifyMappingsTest extends WebTestBase {
+
+  public static $modules = array('node', 'rdf');
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'RDFa modification',
+      'description' => 'Test RDFa markup generation.',
+      'group' => 'Examples',
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setUp() {
+    $this->profile = 'standard';
+    parent::setUp();
+    $this->base_uri = \Drupal::url('<front>', array(), array('absolute' => TRUE));
+  }
+
+  /**
+   * Test that a node type's existing RDF mappings can be modified.
+   */
+  public function testModifyingExistingMappings() {
+
+    $node = $this->drupalCreateNode(array('type' => 'article'));
+
+    $node_title = $node->getTitle();
+    $url = $node->url('canonical', array('absolute' => TRUE));
+
+    $parser = new \EasyRdf_Parser_Rdfa();
+    $graph = new \EasyRdf_Graph();
+
+    $parser->parse($graph, $this->drupalGet($url), 'rdfa', $this->base_uri);
+
+    $expected_title_value = array(
+      'type' => 'literal',
+      'value' => $node_title,
+      'lang' => 'en',
+    );
+
+    // Verify the initial mappings set in the standard install profile.
+    $this->assertTrue(
+      $graph->hasProperty(
+        $this->url, 'http://schema.org/name', $expected_title_value
+      ), 'Article has title mapped to schema:name.'
+    );
+    $this->assertEqual(
+      array('schema:Article'), $graph->types($this->url),
+      'Article has RDF type of schema:Article.'
+    );
+
+    // Modify the type and title field mappings.
+    $config = \Drupal::config('rdf.mapping.node.article');
+    // Change the type mapping from schema:Article.
+    $config->set('types', array('sioc:Post'))
+      ->set('fieldMappings.title.properties', array('dc:title'))
+      ->save();
+
+    $node = $this->drupalCreateNode(array('type' => 'article'));
+    $node_title = $node->getTitle();
+    $url = $node->url('canonical', array('absolute' => TRUE));
+    $expected_title_value = array(
+      'type' => 'literal',
+      'value' => $node_title,
+      'lang' => 'en',
+    );
+
+    $parser->parse($graph, $this->drupalGet($url), 'rdfa', $this->base_uri);
+
+    // Verify that the RDFa output has changed to reflect the new mappings.
+    $this->assertFalse(
+      $graph->hasProperty(
+        $this->url, 'http://schema.org/name', $expected_title_value
+      ), 'Article no longer has title mapped to schema:name.'
+    );
+    $this->assertTrue(
+      $graph->hasProperty(
+        $this->url, 'http://purl.org/dc/terms/title', $expected_title_value
+      ), 'Article now has title mapped to dc:title.'
+    );
+    $this->assertEqual(
+      array('sioc:Post'), $graph->types($this->url),
+      'Article now has RDF type of sioc:Post.'
+    );
+
+    // Test that the provided mapping for the node's creation date are used.
+    $expected_date_value = array(
+      'type' => 'literal',
+      'value' => date('c', $node->getChangedTime()),
+      'lang' => 'en',
+    );
+    $this->assertTrue(
+      $graph->hasProperty($this->url, 'http://schema.org/dateCreated', $expected_date_value),
+      'schema:dateCreated property present for node creation date.'
+    );
+
+  }
+}
diff --git a/rdf_example/rdf_example.info.yml b/rdf_example/rdf_example.info.yml
new file mode 100644
index 0000000..959fa58
--- /dev/null
+++ b/rdf_example/rdf_example.info.yml
@@ -0,0 +1,8 @@
+name: RDF Example
+type: module
+description: 'Demonstrates an RDF mapping using the RDF mapping API.'
+package: Example modules
+core: 8.x
+dependencies:
+  - node
+  - rdf
diff --git a/rdf_example/rdf_example.module b/rdf_example/rdf_example.module
new file mode 100644
index 0000000..ca31840
--- /dev/null
+++ b/rdf_example/rdf_example.module
@@ -0,0 +1,66 @@
+<?php
+/**
+ * @file
+ * This is an example demonstrating the configuration of RDF mappings.
+ */
+
+/**
+ * @defgroup rdf_example Example: RDF
+ * @ingroup examples
+ * @{
+ * RDF mapping example.
+ *
+ * This module defines a 'recipe' node type with 'summary' (text) and 'photo'
+ * (image) fields. RDF mappings for this node type are defined in the file
+ * 'rdf.mapping.node.recipe.yml', rather than invoking hook_rdf_mapping() as
+ * would be the case in Drupal 7.
+ *
+ * This module contains a test case which creates a node of this new type, and
+ * verifies that the correct RDF type and properties are present in the RDFa
+ * content of the node view page.
+ * A second test case alters the type and title field of the 'article' node type
+ * from the standard installation profile using the Configuration API.
+ * (This method of altering existing RDF mappings supersedes the
+ * rdf_mapping_load(), rdf_mapping_save() and rdf_mapping_delete() methods in
+ * Drupal 7.). The test then verifies that the RDFa output of the node pages
+ * changes accordingly.
+ *
+ */
+
+/**
+ * Implements hook_rdf_namespaces().
+ *
+ * This hook should be used to define any prefixes used by this module that are
+ * not already defined in core by rdf_rdf_namespaces().
+ *
+ * @see hook_rdf_namespaces()
+ */
+function rdf_example_rdf_namespaces() {
+  return array(
+    // Google's namespace for their custom vocabularies.
+    'v' => 'http://rdf.data-vocabulary.org/#',
+  );
+}
+
+/**
+ * Implements hook_help().
+ */
+function rdf_example_help($path, $arg) {
+  switch ($path) {
+    case 'examples/rdf_example':
+      return "<p>" . t(
+        "The RDF Example module provides RDF mappings for a custom node type and
+        alters another node type's RDF mapping.
+        You can check your RDF using a <a href='!parser'>parser</a> by copying
+        and pasting your HTML source code into the box. For clearest results,
+        use Turtle as your output format.",
+        array(
+          '!parser' => url('http://www.w3.org/2007/08/pyRdfa/#distill_by_input'),
+        )
+      ) . "</p>";
+  }
+}
+
+/**
+ * @} End of "defgroup rdf_example".
+ */
diff --git a/rdf_example/rdf_example.routing.yml b/rdf_example/rdf_example.routing.yml
new file mode 100644
index 0000000..99ba65f
--- /dev/null
+++ b/rdf_example/rdf_example.routing.yml
@@ -0,0 +1,6 @@
+rdf_example.description:
+  path: 'examples/rdf_example'
+  defaults:
+    _content: '\Drupal\rdf_example\Controller\RDFExampleController::description'
+  requirements:
+    _access: 'TRUE'
