diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000000000000000000000000000000000000..ec9c9dc6da74243090a1f013b73e4b60bbe2656e
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,101 @@
+language: php
+
+# The Travis CI container mode has random functional test fails, so we must use
+# sudo here.
+sudo: true
+
+php:
+  - 7.1
+  - 7.2
+  - 7.3
+
+services:
+  - mysql
+
+env:
+  global:
+    - MODULE=recurring_events
+  matrix:
+    - DRUPAL_CORE=8.8.x DRUSH_VER=9.0
+    - DRUPAL_CORE=8.9.x DRUSH_VER=9.0
+    - DRUPAL_CORE=9.0.x DRUSH_VER=10.0
+
+matrix:
+  fast_finish: true
+  exclude:
+    - php: 7.1
+      env: DRUPAL_CORE=9.0.x DRUSH_VER=10.0
+    - php: 7.2
+      env: DRUPAL_CORE=9.0.x DRUSH_VER=10.0
+
+# Be sure to cache composer downloads.
+cache:
+  directories:
+    - $HOME/.composer
+
+before_script:
+  # Remove Xdebug as we don't need it and it causes
+  # PHP Fatal error:  Maximum function nesting level of '256' reached.
+  # We also don't care if that file exists or not on PHP 7.
+  - phpenv config-rm xdebug.ini || true
+
+  # Navigate out of module directory to prevent blown stack by recursive module
+  # lookup.
+  - cd ..
+
+  # Create database.
+  - mysql -e "create database $MODULE"
+  # Export database variable for kernel tests.
+  - export SIMPLETEST_DB=mysql://root:@127.0.0.1/$MODULE
+
+  # Create a new Drupal project using the appropriate version using Composer.
+  - COMPOSER_MEMORY_LIMIT=-1 composer create-project drupal/recommended-project:$DRUPAL_CORE drupal --stability dev --no-interaction
+  - cd drupal
+  - DRUPAL_ROOT=$(pwd)
+
+  # Add the necessary third party dependencies to run these tests.
+  - COMPOSER_MEMORY_LIMIT=-1 composer require drupal/field_inheritance
+  - COMPOSER_MEMORY_LIMIT=-1 composer require drush/drush:^$DRUSH_VER
+  - COMPOSER_MEMORY_LIMIT=-1 composer require mglaman/drupal-check --dev
+  - COMPOSER_MEMORY_LIMIT=-1 composer require drupal/group:1.x-dev
+
+  - cd $DRUPAL_ROOT
+
+  # The recurring events module artifact is already available, so copy it in
+  # to the contrib module directory so we can run our tests.
+  - cp -R $TRAVIS_BUILD_DIR web/modules/contrib/$MODULE
+
+  # Coder is already installed as part of composer install. We just need to set
+  # the installed_paths to pick up the Drupal standards.
+  - $DRUPAL_ROOT/vendor/bin/phpcs --config-set installed_paths $DRUPAL_ROOT/vendor/drupal/coder/coder_sniffer
+
+  # Export web server URL for browser tests.
+  - export SIMPLETEST_BASE_URL=http://localhost:8888
+
+script:
+  # Install the site using Drush and set up some configuration.
+  - ./vendor/bin/drush site-install standard --yes --account-pass=admin --db-url=$SIMPLETEST_DB
+  - ./vendor/bin/drush config-set system.performance css.preprocess 0 --yes
+  - ./vendor/bin/drush config-set system.performance js.preprocess 0 --yes
+  - ./vendor/bin/drush config-set system.logging error_level all --yes
+
+  # Enable the modules we care to run the tests.
+  - ./vendor/bin/drush en simpletest $MODULE recurring_events_registration recurring_events_views --yes
+
+  # Start up a HTTP server for tests.
+  - ./vendor/bin/drush runserver --default-server=builtin 8888 > /dev/null &
+
+  # Run the PHPUnit tests.
+  - ./vendor/bin/phpunit -c ./web/core/phpunit.xml.dist --verbose --group=$MODULE ./web/modules/contrib/$MODULE
+
+  # Run the deprecation checks.
+  - ./vendor/bin/drupal-check ./web/modules/contrib/$MODULE
+
+  # Check for coding standards. First change directory to our module.
+  - cd $DRUPAL_ROOT/web/modules/contrib/$MODULE
+
+  # Show the violations in detail and do not fail for any errors or warnings.
+  - $DRUPAL_ROOT/vendor/bin/phpcs --standard=drupal,drupalPractice --ignore=vendor --report-width=130 --colors --runtime-set ignore_warnings_on_exit 1 --runtime-set ignore_errors_on_exit 0 .
+
+  # Run again to give a summary and total count.
+  - $DRUPAL_ROOT/vendor/bin/phpcs --standard=drupal,drupalPractice --ignore=vendor --report-width=130 --colors --runtime-set ignore_warnings_on_exit 1 --runtime-set ignore_errors_on_exit 0 --report=summary .
diff --git a/README.md b/README.md
deleted file mode 100644
index 9c2d9b243983cac921dc24f2fc2407d7ba98f426..0000000000000000000000000000000000000000
--- a/README.md
+++ /dev/null
@@ -1,5 +0,0 @@
-Recurring Events (recurring_events)
-============
-
-## Introduction
-The Recurring Events module is a plug-and-play recurring events and registration system designed to be site agnostic and extensible. Detailed information about the module is available on the module's help page at /admin/help/recurring_events.
\ No newline at end of file
diff --git a/composer.json b/composer.json
index 4cc8f4dba4369e720ddd5ad40e48e4ac29ba1d4f..8e57f38c3b3e2179756e2b93e7ef8b7a198f79a6 100644
--- a/composer.json
+++ b/composer.json
@@ -1,7 +1,7 @@
 {
   "name": "drupal/recurring_events",
   "type": "drupal-module",
-  "description": "Events and Registration Management Module",
+  "description": "Recurring Events and Registration Management Module",
   "keywords": ["Drupal"],
   "license": "GPL-2.0+",
   "homepage": "https://www.drupal.org/project/recurring_events",
@@ -10,5 +10,7 @@
     "issues": "https://www.drupal.org/project/issues/recurring_events",
     "source": "http://cgit.drupalcode.org/recurring_events"
   },
-  "require": { }
+  "require": {
+    "drupal/field_inheritance": "^1"
+  }
 }
diff --git a/config/install/core.entity_form_display.eventseries.eventseries.default.yml b/config/install/core.entity_form_display.eventseries.default.default.yml
similarity index 93%
rename from config/install/core.entity_form_display.eventseries.eventseries.default.yml
rename to config/install/core.entity_form_display.eventseries.default.default.yml
index adbba6f41169eb8504e78a44cf1f562dfd1f3cd8..c426d6fde2036971b377315bd578f8e28c2ba9da 100644
--- a/config/install/core.entity_form_display.eventseries.eventseries.default.yml
+++ b/config/install/core.entity_form_display.eventseries.default.default.yml
@@ -1,13 +1,15 @@
 langcode: en
 status: true
 dependencies:
+  config:
+    - recurring_events.eventseries_type.default
   module:
     - datetime_range
     - recurring_events
     - text
-id: eventseries.eventseries.default
+id: eventseries.default.default
 targetEntityType: eventseries
-bundle: eventseries
+bundle: default
 mode: default
 content:
   body:
@@ -26,7 +28,6 @@ content:
     third_party_settings: {  }
   custom_date:
     type: daterange_default
-    label: above
     weight: 7
     region: content
     settings: {  }
@@ -39,14 +40,12 @@ content:
     third_party_settings: {  }
   excluded_dates:
     type: daterange_default
-    label: above
     weight: 8
     settings: {  }
     region: content
     third_party_settings: {  }
   included_dates:
     type: daterange_default
-    label: above
     weight: 9
     settings: {  }
     region: content
@@ -85,6 +84,7 @@ content:
       match_operator: CONTAINS
       size: 60
       placeholder: ''
+      match_limit: 10
     region: content
     third_party_settings: {  }
   weekly_recurring_date:
diff --git a/config/install/core.entity_view_display.eventinstance.eventinstance.default.yml b/config/install/core.entity_view_display.eventinstance.default.default.yml
similarity index 63%
rename from config/install/core.entity_view_display.eventinstance.eventinstance.default.yml
rename to config/install/core.entity_view_display.eventinstance.default.default.yml
index 2fb3cc9959de6528bb382d54b1737d9df443e440..60f6ba50528c91589d6df8912bcf6528359e34b0 100644
--- a/config/install/core.entity_view_display.eventinstance.eventinstance.default.yml
+++ b/config/install/core.entity_view_display.eventinstance.default.default.yml
@@ -1,33 +1,41 @@
 langcode: en
 status: true
 dependencies:
+  config:
+    - recurring_events.eventinstance_type.default
   module:
     - datetime_range
     - recurring_events
     - text
-id: eventinstance.eventinstance.default
+id: eventinstance.default.default
 targetEntityType: eventinstance
-bundle: eventinstance
+bundle: default
 mode: default
 content:
   date:
     label: above
     type: daterange_default
-    weight: 2
+    weight: 1
     settings:
-      fromto: both
-      separator: '-'
-      format_type: medium
       timezone_override: ''
+      format_type: long
+      separator: '-'
     region: content
     third_party_settings: {  }
   description:
     type: text_default
-    weight: 1
+    weight: 2
     region: content
     label: above
     settings: {  }
     third_party_settings: {  }
+  title:
+    type: string
+    weight: 0
+    region: content
+    label: above
+    settings:
+      link_to_entity: false
+    third_party_settings: {  }
 hidden:
   body: true
-  title: true
diff --git a/config/install/core.entity_view_display.eventinstance.default.list.yml b/config/install/core.entity_view_display.eventinstance.default.list.yml
new file mode 100644
index 0000000000000000000000000000000000000000..12fb9f8fed12d19299454b87aa5aaf5e0c9be720
--- /dev/null
+++ b/config/install/core.entity_view_display.eventinstance.default.list.yml
@@ -0,0 +1,42 @@
+langcode: en
+status: true
+dependencies:
+  config:
+    - core.entity_view_mode.eventinstance.list
+    - recurring_events.eventinstance_type.default
+  module:
+    - datetime_range
+    - text
+id: eventinstance.default.list
+targetEntityType: eventinstance
+bundle: default
+mode: list
+content:
+  date:
+    label: hidden
+    type: daterange_default
+    weight: 1
+    settings:
+      timezone_override: ''
+      format_type: short
+      separator: '-'
+    region: content
+    third_party_settings: {  }
+  description:
+    type: text_trimmed
+    weight: 2
+    region: content
+    label: visually_hidden
+    settings:
+      trim_length: 200
+    third_party_settings: {  }
+  title:
+    type: string
+    weight: 0
+    region: content
+    label: hidden
+    settings:
+      link_to_entity: true
+    third_party_settings: {  }
+hidden:
+  body: true
diff --git a/config/install/core.entity_view_display.eventseries.eventseries.default.yml b/config/install/core.entity_view_display.eventseries.default.default.yml
similarity index 77%
rename from config/install/core.entity_view_display.eventseries.eventseries.default.yml
rename to config/install/core.entity_view_display.eventseries.default.default.yml
index cc48ff79b39708cfe0958365b1655346d54af6ac..3ee75d19dd8b25d57c98a3e4babffbebe1615e12 100644
--- a/config/install/core.entity_view_display.eventseries.eventseries.default.yml
+++ b/config/install/core.entity_view_display.eventseries.default.default.yml
@@ -1,49 +1,53 @@
 langcode: en
 status: true
 dependencies:
+  config:
+    - recurring_events.eventseries_type.default
   module:
     - options
     - recurring_events
     - text
-id: eventseries.eventseries.default
+id: eventseries.default.default
 targetEntityType: eventseries
-bundle: eventseries
+bundle: default
 mode: default
 content:
   body:
     label: above
-    weight: 10
+    weight: 1
     region: content
     settings: {  }
     third_party_settings: {  }
     type: text_default
   event_instances:
     type: recurring_events_eventinstance_date
+    weight: 3
+    region: content
     label: above
-    weight: 10
     settings:
-      link: true
+      link: '1'
       date_format: 'F jS, Y h:iA'
       separator: ' - '
-    region: content
     third_party_settings: {  }
   recur_type:
     label: above
-    weight: 10
+    weight: 2
     region: content
     settings: {  }
     third_party_settings: {  }
     type: list_default
   title:
     label: above
-    weight: 10
+    weight: 0
     region: content
     settings:
       link_to_entity: false
     third_party_settings: {  }
     type: string
 hidden:
+  consecutive_recurring_date: true
   custom_date: true
+  daily_recurring_date: true
   event_registration: true
   monthly_recurring_date: true
   weekly_recurring_date: true
diff --git a/config/install/core.entity_view_display.eventseries.default.list.yml b/config/install/core.entity_view_display.eventseries.default.list.yml
new file mode 100644
index 0000000000000000000000000000000000000000..b3f4281ce716f0dec71e8552fb05458707951fac
--- /dev/null
+++ b/config/install/core.entity_view_display.eventseries.default.list.yml
@@ -0,0 +1,38 @@
+langcode: en
+status: true
+dependencies:
+  config:
+    - core.entity_view_mode.eventseries.list
+    - recurring_events.eventseries_type.default
+  module:
+    - text
+id: eventseries.default.list
+targetEntityType: eventseries
+bundle: default
+mode: list
+content:
+  body:
+    label: hidden
+    weight: 1
+    region: content
+    settings:
+      trim_length: 200
+    third_party_settings: {  }
+    type: text_trimmed
+  title:
+    label: hidden
+    weight: 0
+    region: content
+    settings:
+      link_to_entity: true
+    third_party_settings: {  }
+    type: string
+hidden:
+  consecutive_recurring_date: true
+  custom_date: true
+  daily_recurring_date: true
+  event_instances: true
+  event_registration: true
+  monthly_recurring_date: true
+  recur_type: true
+  weekly_recurring_date: true
diff --git a/config/install/core.entity_view_mode.eventinstance.list.yml b/config/install/core.entity_view_mode.eventinstance.list.yml
new file mode 100644
index 0000000000000000000000000000000000000000..4e18aa05bea63b3293396b03c7d2a6d33db3b65b
--- /dev/null
+++ b/config/install/core.entity_view_mode.eventinstance.list.yml
@@ -0,0 +1,9 @@
+langcode: en
+status: true
+dependencies:
+  module:
+    - recurring_events
+id: eventinstance.list
+label: List
+targetEntityType: eventinstance
+cache: true
diff --git a/config/install/core.entity_view_mode.eventseries.list.yml b/config/install/core.entity_view_mode.eventseries.list.yml
new file mode 100644
index 0000000000000000000000000000000000000000..62bae030254fe0ce498a6f2e294b315297deeaf7
--- /dev/null
+++ b/config/install/core.entity_view_mode.eventseries.list.yml
@@ -0,0 +1,9 @@
+langcode: en
+status: true
+dependencies:
+  module:
+    - recurring_events
+id: eventseries.list
+label: List
+targetEntityType: eventseries
+cache: true
diff --git a/config/install/field_inheritance.field_inheritance.eventinstance_default_description.yml b/config/install/field_inheritance.field_inheritance.eventinstance_default_description.yml
new file mode 100644
index 0000000000000000000000000000000000000000..2bd1b02b4bd590fbc3957aa9e6abf596cac353a0
--- /dev/null
+++ b/config/install/field_inheritance.field_inheritance.eventinstance_default_description.yml
@@ -0,0 +1,13 @@
+langcode: en
+status: true
+dependencies: {  }
+id: eventinstance_default_description
+label: Description
+type: append
+sourceEntityType: eventseries
+sourceEntityBundle: default
+sourceField: body
+destinationEntityType: eventinstance
+destinationEntityBundle: default
+destinationField: body
+plugin: default_inheritance
diff --git a/config/install/field_inheritance.field_inheritance.eventinstance_default_title.yml b/config/install/field_inheritance.field_inheritance.eventinstance_default_title.yml
new file mode 100644
index 0000000000000000000000000000000000000000..0332bd54aac1836f84592dcdd36ac6dd03d2bd79
--- /dev/null
+++ b/config/install/field_inheritance.field_inheritance.eventinstance_default_title.yml
@@ -0,0 +1,12 @@
+langcode: en
+status: true
+dependencies: {  }
+id: eventinstance_default_title
+label: Title
+type: inherit
+sourceEntityType: eventseries
+sourceEntityBundle: default
+sourceField: title
+destinationEntityType: eventinstance
+destinationEntityBundle: default
+plugin: default_inheritance
diff --git a/config/install/recurring_events.eventinstance_type.default.yml b/config/install/recurring_events.eventinstance_type.default.yml
new file mode 100644
index 0000000000000000000000000000000000000000..a5b42dd93e4c23460dad80a9b24d14a272830c56
--- /dev/null
+++ b/config/install/recurring_events.eventinstance_type.default.yml
@@ -0,0 +1,6 @@
+langcode: en
+status: true
+dependencies: {  }
+label: Default
+id: default
+description: 'A default event instance type.'
diff --git a/config/install/recurring_events.eventseries_type.default.yml b/config/install/recurring_events.eventseries_type.default.yml
new file mode 100644
index 0000000000000000000000000000000000000000..f3865a6e07eb41be1599329318eb21a13e50ed1a
--- /dev/null
+++ b/config/install/recurring_events.eventseries_type.default.yml
@@ -0,0 +1,6 @@
+langcode: en
+status: true
+dependencies: {  }
+label: Default
+id: default
+description: 'A default event series type.'
diff --git a/config/install/recurring_events.field_inheritance.description.yml b/config/install/recurring_events.field_inheritance.description.yml
deleted file mode 100644
index b775e48a033c4b014426824a036ffe79e895cb9d..0000000000000000000000000000000000000000
--- a/config/install/recurring_events.field_inheritance.description.yml
+++ /dev/null
@@ -1,9 +0,0 @@
-langcode: en
-status: true
-dependencies: {  }
-id: description
-label: Description
-type: append
-sourceField: body
-entityField: body
-plugin: text_inheritance
diff --git a/config/install/recurring_events.field_inheritance.title.yml b/config/install/recurring_events.field_inheritance.title.yml
deleted file mode 100644
index 0ff470604ed269c0e4b921dd600445b9b6ed2d44..0000000000000000000000000000000000000000
--- a/config/install/recurring_events.field_inheritance.title.yml
+++ /dev/null
@@ -1,9 +0,0 @@
-langcode: en
-status: true
-dependencies: {  }
-id: title
-label: Title
-type: inherit
-sourceField: title
-entityField: ''
-plugin: string_inheritance
diff --git a/config/schema/eventinstance_type.schema.yml b/config/schema/eventinstance_type.schema.yml
new file mode 100644
index 0000000000000000000000000000000000000000..a7c8a2157e4d091409d9651bfe180ceeed6ac98f
--- /dev/null
+++ b/config/schema/eventinstance_type.schema.yml
@@ -0,0 +1,15 @@
+recurring_events.eventinstance_type.*:
+  type: config_entity
+  label: 'Event instance type config'
+  mapping:
+    id:
+      type: string
+      label: 'ID'
+    label:
+      type: label
+      label: 'Label'
+    description:
+      type: string
+      label: 'Description'
+    uuid:
+      type: string
diff --git a/config/schema/eventseries_type.schema.yml b/config/schema/eventseries_type.schema.yml
new file mode 100644
index 0000000000000000000000000000000000000000..6b5608ca3d6e7f5a27415543cd2a0c58f77c0236
--- /dev/null
+++ b/config/schema/eventseries_type.schema.yml
@@ -0,0 +1,15 @@
+recurring_events.eventseries_type.*:
+  type: config_entity
+  label: 'Event series type config'
+  mapping:
+    id:
+      type: string
+      label: 'ID'
+    label:
+      type: label
+      label: 'Label'
+    description:
+      type: string
+      label: 'Description'
+    uuid:
+      type: string
diff --git a/config/schema/field_inheritance.schema.yml b/config/schema/field_inheritance.schema.yml
deleted file mode 100644
index 0bde2530d5d0abd2befea9c964422d6cbce2f5c5..0000000000000000000000000000000000000000
--- a/config/schema/field_inheritance.schema.yml
+++ /dev/null
@@ -1,20 +0,0 @@
-recurring_events.field_inheritance.*:
-  type: config_entity
-  label: 'Field inheritance config'
-  mapping:
-    id:
-      type: string
-      label: 'ID'
-    label:
-      type: label
-      label: 'Label'
-    uuid:
-      type: string
-    type:
-      type: string
-    sourceField:
-      type: string
-    entityField:
-      type: string
-    plugin:
-      type: string
diff --git a/config/schema/recurring_events.schema.yml b/config/schema/recurring_events.schema.yml
index 036148ed0dc6f6a3fff11743c2b6545895f4d190..3f8647895bd16555f68a533f629f03c918e9a10c 100644
--- a/config/schema/recurring_events.schema.yml
+++ b/config/schema/recurring_events.schema.yml
@@ -55,3 +55,17 @@ recurring_events.eventinstance.config:
     limit:
       type: integer
       label: 'The items per page to show on event instance listing'
+
+field.formatter.settings.recurring_events_eventinstance_date:
+  type: mapping
+  label: 'Recurring Events Event Instance Date Formatter'
+  mapping:
+    link:
+      type: string
+      label: 'Whether to format the date as a link'
+    date_format:
+      type: string
+      label: 'The date format to use to display the date'
+    separator:
+      type: string
+      label: 'The separator to use between start and end dates'
diff --git a/js/recurring_events_create_form.js b/js/recurring_events_create_form.js
index 80ea729ee5bb8b819dae26e73d6e93955bedbbd9..969c17d681f5cb9e4d07d2a4193fcb43969b3ac8 100644
--- a/js/recurring_events_create_form.js
+++ b/js/recurring_events_create_form.js
@@ -1,3 +1,8 @@
+/**
+ * @file
+ * Javascript functionality for the recurring events create form.
+ */
+
 (function ($) {
   'use strict';
 
@@ -5,7 +10,7 @@
    * Add weekday selection based on date range.
    */
   Drupal.behaviors.recurring_events_weekday_selection = {
-    attach: function(context, settings) {
+    attach: function (context, settings) {
       var weekdays = new Array(7);
       weekdays[0] = "sunday";
       weekdays[1] = "monday";
@@ -16,7 +21,7 @@
       weekdays[6] = "saturday";
 
       // When the weekly occurrence start date is changed.
-      $('#edit-weekly-recurring-date-0-value-date').on('change', function(event) {
+      $('#edit-weekly-recurring-date-0-value-date').on('change', function (event) {
         var value = $(this).val();
         var date_parts = value.split('-');
         if (date_parts.length > 0) {
@@ -24,7 +29,7 @@
           var weekday = weekdays[date.getDay()];
 
           // Remove all the weekday recurrence options.
-          $('#edit-weekly-recurring-date-0-days').find('input').each(function(key, item) {
+          $('#edit-weekly-recurring-date-0-days').find('input').each(function (key, item) {
             $(item).prop('checked', false);
           });
 
@@ -35,7 +40,7 @@
       });
 
       // When the monthly occurrence start date is changed.
-      $('#edit-monthly-recurring-date-0-value-date').on('change', function(event) {
+      $('#edit-monthly-recurring-date-0-value-date').on('change', function (event) {
         var value = $(this).val();
         var date_parts = value.split('-');
         if (date_parts.length > 0) {
@@ -43,7 +48,7 @@
           var weekday = weekdays[date.getDay()];
 
           // Remove all the monthly recurrence options.
-          $('#edit-monthly-recurring-date-0-days').find('input').each(function(key, item) {
+          $('#edit-monthly-recurring-date-0-days').find('input').each(function (key, item) {
             $(item).prop('checked', false);
           });
 
@@ -59,12 +64,12 @@
    * Set end date for excluded and included dates to be the same as the start.
    */
   Drupal.behaviors.recurring_events_excluded_included_dates = {
-    attach: function(context, settings) {
-      $('#edit-excluded-dates-wrapper, #edit-included-dates-wrapper').find('input.form-date').once().on('change', function(e) {
+    attach: function (context, settings) {
+      $('#edit-excluded-dates-wrapper, #edit-included-dates-wrapper').find('input.form-date').once().on('change', function (e) {
         if ($(this).attr('name').includes('[value][date]')) {
           var start_date = this;
           var parent = $(this).closest('.form-wrapper');
-          $(parent).find('input.form-date').each(function(index, item) {
+          $(parent).find('input.form-date').each(function (index, item) {
             if (index == 1) {
               if ($(item).val() == '') {
                 $(item).val($(start_date).val());
@@ -76,4 +81,4 @@
     }
   };
 
-}(jQuery));
\ No newline at end of file
+}(jQuery));
diff --git a/js/recurring_events_date_form.js b/js/recurring_events_date_form.js
index 320d913a5834b1bca536c0e65437fc26e44b1715..69ec49da9df82d73ccdb87d912f4884566fc0ceb 100644
--- a/js/recurring_events_date_form.js
+++ b/js/recurring_events_date_form.js
@@ -1,3 +1,8 @@
+/**
+ * @file
+ * Javascript functionality for the included/excluded date forms.
+ */
+
 (function ($) {
   'use strict';
 
@@ -5,9 +10,9 @@
    * Set end date for excluded and included dates to be the same as the start.
    */
   Drupal.behaviors.recurring_events_excluded_included_config_dates = {
-    attach: function(context, settings) {
+    attach: function (context, settings) {
 
-      $('#edit-start').once().on('change', function(e) {
+      $('#edit-start').once().on('change', function (e) {
         if ($('#edit-end').val() == '') {
           $('#edit-end').val($(this).val());
         }
@@ -15,4 +20,4 @@
     }
   };
 
-}(jQuery));
\ No newline at end of file
+}(jQuery));
diff --git a/modules/recurring_events_registration/README.md b/modules/recurring_events_registration/README.md
index 33e8cf404494c1e62df521200a6dac9dc12517b7..b2009856af1b039a71dfe228b4d766192f682048 100644
--- a/modules/recurring_events_registration/README.md
+++ b/modules/recurring_events_registration/README.md
@@ -2,4 +2,7 @@ Recurring Events (recurring_events)
 ============
 
 ## Introduction
-The Recurring Events Registration module is a submodule of recurring_events. It provides a registration system designed to be site agnostic and extensible. Detailed information about the module is available on the module's help page at /admin/help/recurring_events_registration.
\ No newline at end of file
+The Recurring Events Registration module is a submodule of recurring_events. It
+provides a registration system designed to be site agnostic and extensible.
+Detailed information about the module is available on the module's help page at
+/admin/help/recurring_events_registration.
diff --git a/modules/recurring_events_registration/config/install/core.entity_form_display.registrant.registrant.default.yml b/modules/recurring_events_registration/config/install/core.entity_form_display.registrant.default.default.yml
similarity index 77%
rename from modules/recurring_events_registration/config/install/core.entity_form_display.registrant.registrant.default.yml
rename to modules/recurring_events_registration/config/install/core.entity_form_display.registrant.default.default.yml
index 34e3adb35693b30f1859c6a68d9959924b214f0e..20993e5e8fac93634711e9905af376c28e429a05 100644
--- a/modules/recurring_events_registration/config/install/core.entity_form_display.registrant.registrant.default.yml
+++ b/modules/recurring_events_registration/config/install/core.entity_form_display.registrant.default.default.yml
@@ -2,16 +2,15 @@ langcode: en
 status: true
 dependencies:
   config:
-    - field.field.registrant.registrant.field_first_name
-    - field.field.registrant.registrant.field_last_name
-    - field.field.registrant.registrant.field_phone
+    - field.field.registrant.default.field_first_name
+    - field.field.registrant.default.field_last_name
+    - field.field.registrant.default.field_phone
+    - recurring_events_registration.registrant_type.default
   module:
     - recurring_events_registration
-_core:
-  default_config_hash: ea3xG3Ezt8XlAj9nlwP6v3hT-_F8IcEQHN6pb5OI55g
-id: registrant.registrant.default
+id: registrant.default.default
 targetEntityType: registrant
-bundle: registrant
+bundle: default
 mode: default
 content:
   email:
@@ -53,6 +52,7 @@ content:
       match_operator: CONTAINS
       size: 60
       placeholder: ''
+      match_limit: 10
     region: content
     third_party_settings: {  }
 hidden: {  }
diff --git a/modules/recurring_events_registration/config/install/core.entity_view_display.registrant.registrant.default.yml b/modules/recurring_events_registration/config/install/core.entity_view_display.registrant.default.default.yml
similarity index 75%
rename from modules/recurring_events_registration/config/install/core.entity_view_display.registrant.registrant.default.yml
rename to modules/recurring_events_registration/config/install/core.entity_view_display.registrant.default.default.yml
index 8b773bad3a260802952b453900da37de0dc31456..7b5ac92c750fcebfddc4376fe647f0cab4f30629 100644
--- a/modules/recurring_events_registration/config/install/core.entity_view_display.registrant.registrant.default.yml
+++ b/modules/recurring_events_registration/config/install/core.entity_view_display.registrant.default.default.yml
@@ -2,17 +2,16 @@ langcode: en
 status: true
 dependencies:
   config:
-    - field.field.registrant.registrant.field_first_name
-    - field.field.registrant.registrant.field_last_name
-    - field.field.registrant.registrant.field_phone
+    - field.field.registrant.default.field_first_name
+    - field.field.registrant.default.field_last_name
+    - field.field.registrant.default.field_phone
+    - recurring_events_registration.registrant_type.default
   module:
     - recurring_events_registration
     - user
-_core:
-  default_config_hash: 3clqPdEmzURlNSnHkS8qcIi_HNNeDJgzA336NT77DCE
-id: registrant.registrant.default
+id: registrant.default.default
 targetEntityType: registrant
-bundle: registrant
+bundle: default
 mode: default
 content:
   email:
diff --git a/modules/recurring_events_registration/config/install/core.entity_view_mode.registrant.list.yml b/modules/recurring_events_registration/config/install/core.entity_view_mode.registrant.list.yml
new file mode 100644
index 0000000000000000000000000000000000000000..375bf0a84d6210b5caddc71d3b568645cfe78cba
--- /dev/null
+++ b/modules/recurring_events_registration/config/install/core.entity_view_mode.registrant.list.yml
@@ -0,0 +1,9 @@
+langcode: en
+status: true
+dependencies:
+  module:
+    - recurring_events_registration
+id: registrant.list
+label: List
+targetEntityType: registrant
+cache: true
diff --git a/modules/recurring_events_registration/config/install/field.field.registrant.registrant.field_first_name.yml b/modules/recurring_events_registration/config/install/field.field.registrant.default.field_first_name.yml
similarity index 76%
rename from modules/recurring_events_registration/config/install/field.field.registrant.registrant.field_first_name.yml
rename to modules/recurring_events_registration/config/install/field.field.registrant.default.field_first_name.yml
index 3c4342422f6620f93bc476f35d8913a0e1403abc..3ce536df2037998a5d7e8a405bdb0a8177298a58 100644
--- a/modules/recurring_events_registration/config/install/field.field.registrant.registrant.field_first_name.yml
+++ b/modules/recurring_events_registration/config/install/field.field.registrant.default.field_first_name.yml
@@ -3,12 +3,13 @@ status: true
 dependencies:
   config:
     - field.storage.registrant.field_first_name
+    - recurring_events_registration.registrant_type.default
   module:
     - recurring_events_registration
-id: registrant.registrant.field_first_name
+id: registrant.default.field_first_name
 field_name: field_first_name
 entity_type: registrant
-bundle: registrant
+bundle: default
 label: 'First Name'
 description: 'Enter your first name.'
 required: false
diff --git a/modules/recurring_events_registration/config/install/field.field.registrant.registrant.field_last_name.yml b/modules/recurring_events_registration/config/install/field.field.registrant.default.field_last_name.yml
similarity index 76%
rename from modules/recurring_events_registration/config/install/field.field.registrant.registrant.field_last_name.yml
rename to modules/recurring_events_registration/config/install/field.field.registrant.default.field_last_name.yml
index 28ba1a5127e8f9c89f0cda99eeabf120e15bb841..421a221151e814a7092556c69fa3d898a089f1e5 100644
--- a/modules/recurring_events_registration/config/install/field.field.registrant.registrant.field_last_name.yml
+++ b/modules/recurring_events_registration/config/install/field.field.registrant.default.field_last_name.yml
@@ -3,12 +3,13 @@ status: true
 dependencies:
   config:
     - field.storage.registrant.field_last_name
+    - recurring_events_registration.registrant_type.default
   module:
     - recurring_events_registration
-id: registrant.registrant.field_last_name
+id: registrant.default.field_last_name
 field_name: field_last_name
 entity_type: registrant
-bundle: registrant
+bundle: default
 label: 'Last Name'
 description: 'Enter your last name.'
 required: false
diff --git a/modules/recurring_events_registration/config/install/field.field.registrant.registrant.field_phone.yml b/modules/recurring_events_registration/config/install/field.field.registrant.default.field_phone.yml
similarity index 76%
rename from modules/recurring_events_registration/config/install/field.field.registrant.registrant.field_phone.yml
rename to modules/recurring_events_registration/config/install/field.field.registrant.default.field_phone.yml
index c5f9131451931bddf74082048ddf0f67b0035b76..5a788670e3e98c8d4a98be01245f03dfbefc965c 100644
--- a/modules/recurring_events_registration/config/install/field.field.registrant.registrant.field_phone.yml
+++ b/modules/recurring_events_registration/config/install/field.field.registrant.default.field_phone.yml
@@ -3,12 +3,13 @@ status: true
 dependencies:
   config:
     - field.storage.registrant.field_phone
+    - recurring_events_registration.registrant_type.default
   module:
     - recurring_events_registration
-id: registrant.registrant.field_phone
+id: registrant.default.field_phone
 field_name: field_phone
 entity_type: registrant
-bundle: registrant
+bundle: default
 label: Phone
 description: 'Enter your phone number.'
 required: false
diff --git a/modules/recurring_events_registration/config/install/recurring_events_registration.registrant.config.yml b/modules/recurring_events_registration/config/install/recurring_events_registration.registrant.config.yml
index 2705292b6db083e099c7c6857bc914913be7ee09..54f3f30364dd68323a0433ecf423c39803f632c8 100644
--- a/modules/recurring_events_registration/config/install/recurring_events_registration.registrant.config.yml
+++ b/modules/recurring_events_registration/config/install/recurring_events_registration.registrant.config.yml
@@ -4,7 +4,6 @@ date_format: 'F jS, Y h:iA'
 title: '[registrant:email]'
 email_notifications: true
 registration_notification_enabled: true
-registration_notification_enabled: true
 registration_notification_subject: 'You''ve Successfully Registered'
 registration_notification_body: "Your registration for the [eventinstance:title] [eventinstance:reg_type] was successful.\r\n\r\nModify your registration: [registrant:edit_url]\r\nDelete your registration: [registrant:delete_url]"
 waitlist_notification_enabled: true
@@ -24,4 +23,4 @@ instance_modification_notification_subject: 'An Event Has Been Modified'
 instance_modification_notification_body: "The [eventinstance:title] [eventinstance:reg_type] has been modified, please check back for details.\r\n\r\nModify your registration: [registrant:edit_url]\r\nDelete your registration: [registrant:delete_url]"
 series_modification_notification_enabled: true
 series_modification_notification_subject: 'An Event Series Has Been Modified'
-series_modification_notification_body: 'The [eventinstance:title] [eventinstance:reg_type] has been modified, and all instances have been removed, and your registration has been deleted.'
\ No newline at end of file
+series_modification_notification_body: 'The [eventinstance:title] [eventinstance:reg_type] has been modified, and all instances have been removed, and your registration has been deleted.'
diff --git a/modules/recurring_events_registration/config/install/recurring_events_registration.registrant_type.default.yml b/modules/recurring_events_registration/config/install/recurring_events_registration.registrant_type.default.yml
new file mode 100644
index 0000000000000000000000000000000000000000..cf5ee47afe712292a3b75db734171b56a4340fca
--- /dev/null
+++ b/modules/recurring_events_registration/config/install/recurring_events_registration.registrant_type.default.yml
@@ -0,0 +1,6 @@
+langcode: en
+status: true
+dependencies: {  }
+label: Default
+id: default
+description: 'A default registrant type.'
diff --git a/modules/recurring_events_registration/config/schema/registrant_type.schema.yml b/modules/recurring_events_registration/config/schema/registrant_type.schema.yml
new file mode 100644
index 0000000000000000000000000000000000000000..cb4bb3f81360050d8bd5d6aa18ec406dfff7bd17
--- /dev/null
+++ b/modules/recurring_events_registration/config/schema/registrant_type.schema.yml
@@ -0,0 +1,15 @@
+recurring_events_registration.registrant_type.*:
+  type: config_entity
+  label: 'registrant type config'
+  mapping:
+    id:
+      type: string
+      label: 'ID'
+    label:
+      type: label
+      label: 'Label'
+    description:
+      type: string
+      label: 'Description'
+    uuid:
+      type: string
diff --git a/modules/recurring_events_registration/recurring_events_registration.api.php b/modules/recurring_events_registration/recurring_events_registration.api.php
index d928c67de1c4fdc54ab3d74de54a573467c0a74f..59df1093b034a21e5fd70551dba98a7815635c27 100644
--- a/modules/recurring_events_registration/recurring_events_registration.api.php
+++ b/modules/recurring_events_registration/recurring_events_registration.api.php
@@ -24,6 +24,7 @@ use Drupal\recurring_events_registration\Entity\Registrant;
  */
 function hook_recurring_events_registration_first_waitlist_alter(Registrant $registrant) {
   // Find the ID of the registrant you wish to promote, then load the entity.
+  $id = 1234567;
   $new_registrant = \Drupal::entityTypeManager()->getStorage('registrant')->load($id);
   return $new_registrant;
 }
diff --git a/modules/recurring_events_registration/recurring_events_registration.install b/modules/recurring_events_registration/recurring_events_registration.install
index bb121908b0cb89d4787b31ca641e82de8f943f59..aab9be8a4f3d96cf543f48381a1034e3f0bc1447 100644
--- a/modules/recurring_events_registration/recurring_events_registration.install
+++ b/modules/recurring_events_registration/recurring_events_registration.install
@@ -26,11 +26,25 @@ function recurring_events_registration_install() {
     ->setRequired(FALSE)
     ->setDisplayOptions('form', [
       'type' => 'event_registration',
-      'weight' => 4,
+      'weight' => 10,
     ]);
 
   \Drupal::entityDefinitionUpdateManager()
     ->installFieldStorageDefinition('event_registration', 'eventseries', 'eventseries', $storage_definition);
+
+  // When enabling registrations make sure we create all the registrant types
+  // to match the existing series and instance types.
+  foreach (\Drupal::entityTypeManager()->getStorage('eventseries_type')->loadMultiple() as $type) {
+    $registrant_type = \Drupal::entityTypeManager()->getStorage('registrant_type')->load($type->id());
+    if (empty($registrant_type)) {
+      $registrant_type = \Drupal::entityTypeManager()->getStorage('registrant_type')->create([
+        'id' => $type->id(),
+        'label' => $type->label(),
+        'description' => $type->getDescription(),
+      ]);
+      $registrant_type->save();
+    }
+  }
 }
 
 /**
@@ -51,3 +65,16 @@ function recurring_events_registration_update_8001() {
     ->set('title', '[registrant:email]')
     ->save(TRUE);
 }
+
+/**
+ * Install the new type basefields for registrant.
+ */
+function recurring_events_registration_update_8002() {
+  $registrant_type = BaseFieldDefinition::create('entity_reference')
+    ->setLabel(t('Bundle'))
+    ->setDescription(t('The registrant type.'))
+    ->setSetting('target_type', 'registrant_type')
+    ->setReadOnly(TRUE);
+
+  \Drupal::entityDefinitionUpdateManager()->installFieldStorageDefinition('bundle', 'registrant', 'registrant', $registrant_type);
+}
diff --git a/modules/recurring_events_registration/recurring_events_registration.links.action.yml b/modules/recurring_events_registration/recurring_events_registration.links.action.yml
index ca2e9c9451f4077768ca78776ed34fc0c0120e9d..f453125a4228686b99da3053a0e3d14a2f5fa821 100644
--- a/modules/recurring_events_registration/recurring_events_registration.links.action.yml
+++ b/modules/recurring_events_registration/recurring_events_registration.links.action.yml
@@ -3,4 +3,5 @@ entity.registrant.instance_contact:
   route_name: entity.registrant.instance_contact
   title: 'Contact Registrants'
   appears_on:
-    - entity.registrant.instance_listing
\ No newline at end of file
+    - entity.registrant.instance_listing
+    - view.registrations.event_registrant_list
diff --git a/modules/recurring_events_registration/recurring_events_registration.links.menu.yml b/modules/recurring_events_registration/recurring_events_registration.links.menu.yml
index 5ba44cb2d70cfb5bf7d30e6b7e4183666a6c8644..7881024c5b7a99e2f11b4a1578a23dcb6f728d76 100644
--- a/modules/recurring_events_registration/recurring_events_registration.links.menu.yml
+++ b/modules/recurring_events_registration/recurring_events_registration.links.menu.yml
@@ -2,14 +2,22 @@
 # Registrant menu items definition
 entity.registrant.collection:
   title: 'Registrants'
-  route_name: entity.registrant.collection
+  route_name: entity.registrant.admin_collection
   description: 'List Registrant entities'
   parent: events.admin.content
   weight: 100
 
 registrant.admin.structure.settings:
-  title: 'Registrant settings'
+  title: 'Registrant Settings'
   description: 'Configure Registrant entities'
   route_name: registrant.settings
   parent: events.admin.overview
   weight: 12
+
+# Registrant types admin page.
+entity.registrant_type.collection:
+  title: 'Registrant Types'
+  description: 'Configure Registrant Types'
+  route_name: entity.registrant_type.collection
+  parent: events.admin.overview
+  weight: 13
diff --git a/modules/recurring_events_registration/recurring_events_registration.module b/modules/recurring_events_registration/recurring_events_registration.module
index c2ae082d7c26343361965ee0b163f7a2ed152fce..3b489adc3e2157ac78f713fd672f13637a08c9d4 100644
--- a/modules/recurring_events_registration/recurring_events_registration.module
+++ b/modules/recurring_events_registration/recurring_events_registration.module
@@ -122,7 +122,7 @@ function recurring_events_registration_entity_base_field_info_alter(&$fields, En
       ->setTargetEntityTypeId($entity_type->id())
       ->setDisplayOptions('form', [
         'type' => 'event_registration',
-        'weight' => 4,
+        'weight' => 10,
       ]);
   }
 }
@@ -162,10 +162,6 @@ function template_preprocess_registrant(array &$variables) {
  * Implements hook_mail().
  */
 function recurring_events_registration_mail($key, &$message, $params) {
-  $options = [
-    'langcode' => $message['langcode'],
-  ];
-
   $service = \Drupal::service('recurring_events_registration.notification_service');
   $service->setKey($key)->setEntity($params['registrant']);
 
@@ -359,3 +355,77 @@ function recurring_events_registration_entity_operation(EntityInterface $entity)
 
   return $operations;
 }
+
+/**
+ * Implements hook_entity_operation_alter().
+ */
+function recurring_events_registration_entity_operation_alter(array &$operations, EntityInterface $entity) {
+  if ($entity->getEntityTypeId() == 'registrant_type') {
+    if (!empty($operations['delete'])) {
+      unset($operations['delete']);
+    }
+  }
+}
+
+/**
+ * Implements hook_theme_suggestions_HOOK().
+ */
+function recurring_events_registration_theme_suggestions_registrant(array $variables) {
+  $suggestions = [];
+  $entity = $variables['elements']['#registrant'];
+  $sanitized_view_mode = strtr($variables['elements']['#view_mode'], '.', '_');
+
+  $suggestions[] = 'registrant__' . $sanitized_view_mode;
+  $suggestions[] = 'registrant__' . $entity->bundle();
+  $suggestions[] = 'registrant__' . $entity->bundle() . '__' . $sanitized_view_mode;
+  $suggestions[] = 'registrant__' . $entity->id();
+  $suggestions[] = 'registrant__' . $entity->id() . '__' . $sanitized_view_mode;
+  return $suggestions;
+}
+
+/**
+ * Implements hook_ENTITY_TYPE_insert().
+ */
+function recurring_events_registration_registrant_insert(EntityInterface $entity) {
+  $entity_type = $entity->getEntityTypeId();
+  $bundle = $entity->bundle();
+  $inherited_field_ids = \Drupal::entityQuery('field_inheritance')
+    ->condition('sourceEntityType', ['eventseries', 'eventinstance'], 'IN')
+    ->condition('destinationEntityType', $entity_type)
+    ->condition('destinationEntityBundle', $bundle)
+    ->execute();
+
+  if (!empty($inherited_field_ids)) {
+    $state_key = $entity_type . ':' . $entity->uuid();
+    $state = \Drupal::keyValue('field_inheritance');
+    $state_values = $state->get($state_key);
+
+    $inherited_fields = \Drupal::entityTypeManager()->getStorage('field_inheritance')->loadMultiple($inherited_field_ids);
+    $state_values = [
+      'enabled' => TRUE,
+    ];
+    if (!empty($inherited_fields)) {
+      foreach ($inherited_fields as $inherited_field) {
+        $name = $inherited_field->idWithoutTypeAndBundle();
+
+        $referenced_entity = NULL;
+        switch ($inherited_field->sourceEntityType()) {
+          case 'eventseries':
+            $referenced_entity = $entity->getEventSeries();
+            break;
+
+          case 'eventinstance':
+            $referenced_entity = $entity->getEventInstance();
+            break;
+
+        }
+        if (!empty($referenced_entity)) {
+          $state_values[$name] = [
+            'entity' => $referenced_entity->id(),
+          ];
+        }
+      }
+    }
+    $state->set($state_key, $state_values);
+  }
+}
diff --git a/modules/recurring_events_registration/recurring_events_registration.permissions.yml b/modules/recurring_events_registration/recurring_events_registration.permissions.yml
index 315ed22b5254e78c347058de5ca5c8e0ff9159be..d86dd49dfba62d3a77cf63e91961e496d9557c75 100644
--- a/modules/recurring_events_registration/recurring_events_registration.permissions.yml
+++ b/modules/recurring_events_registration/recurring_events_registration.permissions.yml
@@ -32,10 +32,14 @@ resend registrant emails:
 contact registrants:
   title: 'Contact registrants'
   decription: 'Allow a role to set contact registrants'
-administer registrant entities:
+administer registrant entity:
   title: 'Administer registrant entities'
   description: 'Allow to access the administration form to configure registrant entities'
   restrict access: true
+administer registrant types:
+  title: 'Administer registrant types'
+  description: 'Manage types of registrant'
+  restrict access: true
 
 # Registrant Administration.
 access registrant overview:
diff --git a/modules/recurring_events_registration/recurring_events_registration.routing.yml b/modules/recurring_events_registration/recurring_events_registration.routing.yml
index 6b310fc18ded43bdd606a165547bf4c0c1904010..c80f322d6c7ea2c8e06abc8e195ebeae9c07b097 100644
--- a/modules/recurring_events_registration/recurring_events_registration.routing.yml
+++ b/modules/recurring_events_registration/recurring_events_registration.routing.yml
@@ -15,6 +15,8 @@ entity.registrant.admin_collection:
     _title: 'Registrations'
   requirements:
     _permission: 'access registrant overview'
+  options:
+    _admin_route: TRUE
 
 # Registrant settings admin page.
 registrant.settings:
@@ -27,7 +29,7 @@ registrant.settings:
 
 # Registrant view route.
 entity.registrant.canonical:
-  path: '/events/{eventinstance}/registration/{registrant}'
+  path: '/events/{eventinstance}/registrations/{registrant}'
   defaults:
     _entity_view: 'registrant'
     _title_callback: '\Drupal\recurring_events_registration\Controller\RegistrantController::getTitle'
@@ -42,7 +44,7 @@ entity.registrant.canonical:
 
 # Registrant add route.
 entity.registrant.add_form:
-  path: '/events/{eventinstance}/registration/add'
+  path: '/events/{eventinstance}/registrations/add'
   defaults:
   # Calls the form.add controller, defined in the Registrant entity.
     _entity_form: registrant.add
@@ -56,7 +58,7 @@ entity.registrant.add_form:
 
 # Registrant edit route.
 entity.registrant.edit_form:
-  path: '/events/{eventinstance}/registration/{registrant}/edit'
+  path: '/events/{eventinstance}/registrations/{registrant}/edit'
   defaults:
   # Calls the form.edit controller, defined in the Registrant entity.
     _entity_form: registrant.edit
@@ -72,7 +74,7 @@ entity.registrant.edit_form:
 
 # Registrant delete route.
 entity.registrant.delete_form:
-  path: '/events/{eventinstance}/registration/{registrant}/delete'
+  path: '/events/{eventinstance}/registrations/{registrant}/delete'
   defaults:
     # Calls the form.delete controller, defined in the Registrant entity.
     _entity_form: registrant.delete
@@ -88,7 +90,7 @@ entity.registrant.delete_form:
 
 # Resend Registrant email.
 entity.registrant.resend_form:
-  path: '/events/{eventinstance}/registration/{registrant}/resend'
+  path: '/events/{eventinstance}/registrations/{registrant}/resend'
   defaults:
     _form: \Drupal\recurring_events_registration\Form\RegistrantResendForm
     _title: 'Resend Registration Email'
@@ -103,7 +105,7 @@ entity.registrant.resend_form:
 
 # Registrant anonymous edit route.
 entity.registrant.anon_edit_form:
-  path: '/events/{eventinstance}/registration/{registrant}/{uuid}/edit'
+  path: '/events/{eventinstance}/registrations/{registrant}/{uuid}/edit'
   defaults:
   # Calls the form.edit controller, defined in the Registrant entity.
     _entity_form: registrant.edit
@@ -121,7 +123,7 @@ entity.registrant.anon_edit_form:
 
 # Registrant anonymous delete route.
 entity.registrant.anon_delete_form:
-  path: '/events/{eventinstance}/registration/{registrant}/{uuid}/delete'
+  path: '/events/{eventinstance}/registrations/{registrant}/{uuid}/delete'
   defaults:
   # Calls the form.delete controller, defined in the Registrant entity.
     _entity_form: registrant.delete
@@ -177,4 +179,15 @@ entity.registrant.instance_contact:
   options:
     parameters:
       eventinstance:
-        type: entity:eventinstance
\ No newline at end of file
+        type: entity:eventinstance
+
+# Registrant types route.
+entity.registrant_type.collection:
+  path: '/admin/structure/events/registrant/types'
+  defaults:
+    _entity_list: 'registrant_type'
+    _title: 'Registrant types'
+  requirements:
+    _permission: 'administer registrant types'
+  options:
+    _admin_route: TRUE
diff --git a/modules/recurring_events_registration/recurring_events_registration.services.yml b/modules/recurring_events_registration/recurring_events_registration.services.yml
index 121738644419547c2e40dc94976ca1655d0190b3..08712920f23cabbe5511146279dafb96cccc7da8 100644
--- a/modules/recurring_events_registration/recurring_events_registration.services.yml
+++ b/modules/recurring_events_registration/recurring_events_registration.services.yml
@@ -5,4 +5,6 @@ services:
   recurring_events_registration.notification_service:
     class: Drupal\recurring_events_registration\NotificationService
     arguments: ['@string_translation', '@config.factory', '@logger.factory', '@messenger', '@token', '@module_handler', '@recurring_events_registration.creation_service']
-    
\ No newline at end of file
+  recurring_events_registration.access_handler:
+    class: Drupal\recurring_events_registration\AccessHandler
+    arguments: ['@string_translation', '@recurring_events_registration.creation_service', '@current_route_match', '@entity_type.manager']
diff --git a/modules/recurring_events_registration/recurring_events_registration.tokens.inc b/modules/recurring_events_registration/recurring_events_registration.tokens.inc
index 85e0b02a5672697a8df1fbf394352dd08a59ca23..b59cbe898549d2b138672b33bc2876aa638c1114 100644
--- a/modules/recurring_events_registration/recurring_events_registration.tokens.inc
+++ b/modules/recurring_events_registration/recurring_events_registration.tokens.inc
@@ -70,7 +70,6 @@ function recurring_events_registration_tokens($type, $tokens, array $data, array
   $replacements = [];
   if ($type == 'eventinstance' && !empty($data['eventinstance'])) {
     $event_instance = $data['eventinstance'];
-    $event_series = $event_instance->getEventSeries();
     $creation_service = \Drupal::service('recurring_events_registration.creation_service');
     $creation_service->setEventInstance($event_instance);
     foreach ($tokens as $name => $original) {
diff --git a/modules/recurring_events_registration/recurring_events_registration.views.inc b/modules/recurring_events_registration/recurring_events_registration.views.inc
new file mode 100644
index 0000000000000000000000000000000000000000..092da90d3615bfe787c9311eb320693f133014cc
--- /dev/null
+++ b/modules/recurring_events_registration/recurring_events_registration.views.inc
@@ -0,0 +1,14 @@
+<?php
+
+/**
+ * @file
+ * Views functionality for the recurring_events_registration module.
+ */
+
+/**
+ * Implements hook_views_data_alter().
+ */
+function recurring_events_registration_views_data_alter(array &$data) {
+  // Set the default field for a view based on registrants.
+  $data['registrant']['table']['base']['defaults']['field'] = 'email';
+}
diff --git a/modules/recurring_events_registration/src/AccessHandler.php b/modules/recurring_events_registration/src/AccessHandler.php
new file mode 100644
index 0000000000000000000000000000000000000000..0b4f3208c2380b3b1ade63cf20ddbe7977148e35
--- /dev/null
+++ b/modules/recurring_events_registration/src/AccessHandler.php
@@ -0,0 +1,127 @@
+<?php
+
+namespace Drupal\recurring_events_registration;
+
+use Drupal\Core\StringTranslation\TranslationInterface;
+use Drupal\Core\Session\AccountInterface;
+use Symfony\Component\Routing\Route;
+use Drupal\Core\Access\AccessResult;
+use Drupal\Core\Routing\CurrentRouteMatch;
+use Drupal\recurring_events\EventInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+use Drupal\Core\Entity\EntityTypeManagerInterface;
+
+/**
+ * AccessHandler class definition.
+ */
+class AccessHandler {
+  /**
+   * The translation interface.
+   *
+   * @var \Drupal\Core\StringTranslation\TranslationInterface
+   */
+  private $translation;
+
+  /**
+   * The registration creation service.
+   *
+   * @var \Drupal\recurring_events_registration\RegistrationCreationService
+   */
+  protected $creationService;
+
+  /**
+   * The current route match.
+   *
+   * @var \Drupal\Core\Routing\CurrentRouteMatch
+   */
+  protected $routeMatch;
+
+  /**
+   * The entity type manager service.
+   *
+   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
+   */
+  protected $entityTypeManager;
+
+  /**
+   * Class constructor.
+   *
+   * @param \Drupal\Core\StringTranslation\TranslationInterface $translation
+   *   The translation interface.
+   * @param \Drupal\recurring_events_registration\RegistrationCreationService $creation_service
+   *   The registration creation service.
+   * @param Drupal\Core\Routing\CurrentRouteMatch $route_match
+   *   The current route match.
+   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
+   *   The entity type manager service.
+   */
+  public function __construct(TranslationInterface $translation, RegistrationCreationService $creation_service, CurrentRouteMatch $route_match, EntityTypeManagerInterface $entity_type_manager) {
+    $this->translation = $translation;
+    $this->creationService = $creation_service;
+    $this->routeMatch = $route_match;
+    $this->entityTypeManager = $entity_type_manager;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container) {
+    return new static(
+      $container->get('string_translation'),
+      $container->get('recurring_events_registration.creation_service'),
+      $container->get('current_route_match'),
+      $container->get('entity_type.manager')
+    );
+  }
+
+  /**
+   * Access control based on whether event has registration.
+   *
+   * @return bool
+   *   TRUE if event has registration, FALSE otherwise.
+   */
+  public function eventHasRegistration() {
+    $has_registration = FALSE;
+    $event_instance = $this->routeMatch->getParameter('eventinstance');
+    if (!empty($event_instance)) {
+
+      if (!$event_instance instanceof EventInterface && is_numeric($event_instance)) {
+        $event_instance = $this->entityTypeManager->getStorage('eventinstance')->load($event_instance);
+      }
+
+      if ($event_instance instanceof EventInterface) {
+        $this->creationService->setEventInstance($event_instance);
+        $has_registration = $this->creationService->hasRegistration();
+      }
+    }
+    return $has_registration;
+  }
+
+  /**
+   * Access control based on whether the account has the right permission.
+   *
+   * @param Drupal\Core\Session\AccountInterface $account
+   *   The current route.
+   *
+   * @return bool
+   *   TRUE if user has access, FALSE otherwise.
+   */
+  public function userHasPermission(AccountInterface $account) {
+    return $account->hasPermission('access registrant overview');
+  }
+
+  /**
+   * Access control for the Event Registration List view.
+   */
+  public function eventRegistrationListAccess(AccountInterface $account, Route $route) {
+    if (!$this->eventHasRegistration()) {
+      return AccessResult::forbidden();
+    }
+
+    if (!$this->userHasPermission($account)) {
+      return AccessResult::forbidden();
+    }
+    return AccessResult::allowed();
+  }
+
+}
diff --git a/modules/recurring_events_registration/src/Controller/RegistrantController.php b/modules/recurring_events_registration/src/Controller/RegistrantController.php
index 8e2d9651cf563edd93e7f35c4b3c84b0b8027dc8..63bd10570cbf4b422324aec6f3243ee98f134b88 100644
--- a/modules/recurring_events_registration/src/Controller/RegistrantController.php
+++ b/modules/recurring_events_registration/src/Controller/RegistrantController.php
@@ -10,7 +10,7 @@ use Drupal\recurring_events_registration\Entity\RegistrantInterface;
 use Drupal\Core\Access\AccessResult;
 use Drupal\recurring_events\Entity\EventInstance;
 use Drupal\Core\Session\AccountProxyInterface;
-use Drupal\user\Entity\User;
+use Drupal\Core\Entity\EntityTypeManagerInterface;
 
 /**
  * The RegistrantController class.
@@ -31,6 +31,13 @@ class RegistrantController extends ControllerBase implements ContainerInjectionI
    */
   protected $currentUser;
 
+  /**
+   * The entity type manager service.
+   *
+   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
+   */
+  protected $entityTypeManager;
+
   /**
    * Constructs a RegistrantController object.
    *
@@ -38,10 +45,13 @@ class RegistrantController extends ControllerBase implements ContainerInjectionI
    *   The renderer service.
    * @param \Drupal\Core\Session\AccountProxyInterface $current_user
    *   The current user.
+   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
+   *   The entity type manager service.
    */
-  public function __construct(RendererInterface $renderer, AccountProxyInterface $current_user) {
+  public function __construct(RendererInterface $renderer, AccountProxyInterface $current_user, EntityTypeManagerInterface $entity_type_manager) {
     $this->renderer = $renderer;
     $this->currentUser = $current_user;
+    $this->entityTypeManager = $entity_type_manager;
   }
 
   /**
@@ -50,7 +60,8 @@ class RegistrantController extends ControllerBase implements ContainerInjectionI
   public static function create(ContainerInterface $container) {
     return new static(
       $container->get('renderer'),
-      $container->get('current_user')
+      $container->get('current_user'),
+      $container->get('entity_type.manager')
     );
   }
 
@@ -88,7 +99,7 @@ class RegistrantController extends ControllerBase implements ContainerInjectionI
    */
   public function canContactRegistrants(EventInstance $eventinstance) {
     if (!empty($eventinstance)) {
-      $account = User::load($this->currentUser->id());
+      $account = $this->entityTypeManager->getStorage('user')->load($this->currentUser->id());
       return AccessResult::allowedIfHasPermission($account, 'contact registrants');
     }
     return AccessResult::forbidden();
diff --git a/modules/recurring_events_registration/src/Entity/Registrant.php b/modules/recurring_events_registration/src/Entity/Registrant.php
index 38319be24449d88df99e4cf5cb8d805c9c41b121..37a2293317986a99c4189ee8044be46df8d3f280 100644
--- a/modules/recurring_events_registration/src/Entity/Registrant.php
+++ b/modules/recurring_events_registration/src/Entity/Registrant.php
@@ -20,6 +20,7 @@ use Drupal\recurring_events_registration\Plugin\Field\ComputedRegistrantTitleFie
  * @ContentEntityType(
  *   id = "registrant",
  *   label = @Translation("Registrant"),
+ *   bundle_label = @Translation("Registrant type"),
  *   handlers = {
  *     "view_builder" = "Drupal\Core\Entity\EntityViewBuilder",
  *     "list_builder" = "Drupal\recurring_events_registration\RegistrantListBuilder",
@@ -44,15 +45,17 @@ use Drupal\recurring_events_registration\Plugin\Field\ComputedRegistrantTitleFie
  *     "uuid" = "uuid",
  *     "uid" = "user_id",
  *     "label" = "title",
+ *     "bundle" = "bundle",
  *   },
  *   links = {
- *     "canonical" = "/events/{eventinstance}/registrant/{registrant}",
- *     "edit-form" = "/events/{eventinstance}/registrant/{registrant}/edit",
- *     "delete-form" = "/events/{eventinstance}/registrant/{registrant}/delete",
- *     "anon-edit-form" = "/events/{eventinstance}/registrant/{registrant}/{uuid}/edit",
- *     "anon-delete-form" = "/events/{eventinstance}/registrant/{registrant}/{uuid}/delete"
+ *     "canonical" = "/events/{eventinstance}/registrations//{registrant}",
+ *     "edit-form" = "/events/{eventinstance}/registrations//{registrant}/edit",
+ *     "delete-form" = "/events/{eventinstance}/registrations/{registrant}/delete",
+ *     "anon-edit-form" = "/events/{eventinstance}/registrations/{registrant}/{uuid}/edit",
+ *     "anon-delete-form" = "/events/{eventinstance}/registrations/{registrant}/{uuid}/delete"
  *   },
- *   field_ui_base_route = "registrant.settings"
+ *   bundle_entity_type = "registrant_type",
+ *   field_ui_base_route = "entity.registrant_type.edit_form"
  * )
  */
 class Registrant extends ContentEntityBase implements RegistrantInterface {
@@ -66,6 +69,7 @@ class Registrant extends ContentEntityBase implements RegistrantInterface {
     parent::preCreate($storage_controller, $values);
     $values += [
       'user_id' => \Drupal::currentUser()->id(),
+      'bundle' => !empty(\Drupal::request()->attributes->get('eventinstance')) ? \Drupal::request()->attributes->get('eventinstance')->getType() : 'default',
     ];
   }
 
@@ -83,6 +87,13 @@ class Registrant extends ContentEntityBase implements RegistrantInterface {
     }
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function getBundle() {
+    return $this->bundle();
+  }
+
   /**
    * {@inheritdoc}
    */
@@ -152,6 +163,7 @@ class Registrant extends ContentEntityBase implements RegistrantInterface {
           'size' => '60',
           'autocomplete_type' => 'tags',
           'placeholder' => '',
+          'match_limit' => 10,
         ],
       ])
       ->setDisplayConfigurable('form', TRUE)
@@ -176,6 +188,12 @@ class Registrant extends ContentEntityBase implements RegistrantInterface {
       ->setDescription(t('The UUID of the registrant entity.'))
       ->setReadOnly(TRUE);
 
+    $fields['bundle'] = BaseFieldDefinition::create('entity_reference')
+      ->setLabel(t('Bundle'))
+      ->setDescription(t('The registrant type.'))
+      ->setSetting('target_type', 'registrant_type')
+      ->setReadOnly(TRUE);
+
     $fields['eventseries_id'] = BaseFieldDefinition::create('entity_reference')
       ->setLabel(t('Event Series ID'))
       ->setDescription(t('The ID of the eventseries entity.'))
diff --git a/modules/recurring_events_registration/src/Entity/RegistrantType.php b/modules/recurring_events_registration/src/Entity/RegistrantType.php
new file mode 100644
index 0000000000000000000000000000000000000000..7a761d81f386843c8ab8d53def9c0292145d69ec
--- /dev/null
+++ b/modules/recurring_events_registration/src/Entity/RegistrantType.php
@@ -0,0 +1,80 @@
+<?php
+
+namespace Drupal\recurring_events_registration\Entity;
+
+use Drupal\Core\Config\Entity\ConfigEntityBundleBase;
+
+/**
+ * Defines the registrant type entity.
+ *
+ * @ConfigEntityType(
+ *   id = "registrant_type",
+ *   label = @Translation("registrant type"),
+ *   handlers = {
+ *     "view_builder" = "Drupal\Core\Entity\EntityViewBuilder",
+ *     "list_builder" = "Drupal\recurring_events_registration\RegistrantTypeListBuilder",
+ *     "form" = {
+ *       "edit" = "Drupal\recurring_events_registration\Form\RegistrantTypeForm",
+ *     },
+ *     "route_provider" = {
+ *       "html" = "Drupal\recurring_events_registration\RegistrantTypeHtmlRouteProvider",
+ *     },
+ *   },
+ *   config_prefix = "registrant_type",
+ *   bundle_of = "registrant",
+ *   admin_permission = "administer registrant entity",
+ *   entity_keys = {
+ *     "id" = "id",
+ *     "label" = "label",
+ *     "uuid" = "uuid"
+ *   },
+ *   links = {
+ *     "canonical" = "/admin/structure/events/registrants/types/registrant_type/{registrant_type}",
+ *     "edit-form" = "/admin/structure/events/registrants/types/registrant_type/{registrant_type}/edit",
+ *     "collection" = "/admin/structure/events/registrants/types/registrant_type"
+ *   },
+ *   config_export = {
+ *     "label",
+ *     "id",
+ *     "description",
+ *   }
+ * )
+ */
+class RegistrantType extends ConfigEntityBundleBase implements RegistrantTypeInterface {
+
+  /**
+   * The registrant type ID.
+   *
+   * @var string
+   */
+  protected $id;
+
+  /**
+   * The registrant type label.
+   *
+   * @var string
+   */
+  protected $label;
+
+  /**
+   * A brief description of this Registrant type.
+   *
+   * @var string
+   */
+  protected $description;
+
+  /**
+   * {@inheritdoc}
+   */
+  public function id() {
+    return $this->id;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getDescription() {
+    return $this->description;
+  }
+
+}
diff --git a/modules/recurring_events_registration/src/Entity/RegistrantTypeInterface.php b/modules/recurring_events_registration/src/Entity/RegistrantTypeInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..661a38a3bca275350f079e83ce2fc0ebe61907c9
--- /dev/null
+++ b/modules/recurring_events_registration/src/Entity/RegistrantTypeInterface.php
@@ -0,0 +1,20 @@
+<?php
+
+namespace Drupal\recurring_events_registration\Entity;
+
+use Drupal\Core\Config\Entity\ConfigEntityInterface;
+
+/**
+ * Provides an interface for defining Registrant type entities.
+ */
+interface RegistrantTypeInterface extends ConfigEntityInterface {
+
+  /**
+   * Gets the description.
+   *
+   * @return string
+   *   The description of this Registrant type.
+   */
+  public function getDescription();
+
+}
diff --git a/modules/recurring_events_registration/src/Form/ContactForm.php b/modules/recurring_events_registration/src/Form/ContactForm.php
index 725380ba9c25ab4994355a8ccf8fdede2dc6c728..047adabc1621305552133349df01717a60471db2 100644
--- a/modules/recurring_events_registration/src/Form/ContactForm.php
+++ b/modules/recurring_events_registration/src/Form/ContactForm.php
@@ -11,9 +11,9 @@ use Drupal\recurring_events_registration\NotificationService;
 use Drupal\Core\Messenger\Messenger;
 use Drupal\Core\Mail\MailManager;
 use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
-use Drupal\recurring_events\Entity\EventInstance;
 use Drupal\Core\Link;
 use Drupal\Core\Url;
+use Drupal\Core\Language\LanguageManagerInterface;
 
 /**
  * Registrant contact form.
@@ -62,6 +62,13 @@ class ContactForm extends FormBase {
    */
   protected $eventInstance;
 
+  /**
+   * The language manager service.
+   *
+   * @var \Drupal\Core\Language\LanguageManagerInterface
+   */
+  protected $languageManager;
+
   /**
    * Constructs a ContactForm object.
    *
@@ -75,13 +82,16 @@ class ContactForm extends FormBase {
    *   The messenger service.
    * @param \Drupal\Core\Mail\MailManager $mail
    *   The mail manager service.
+   * @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
+   *   The language manager service.
    */
-  public function __construct(RequestStack $request, RegistrationCreationService $creation_service, NotificationService $notification_service, Messenger $messenger, MailManager $mail) {
+  public function __construct(RequestStack $request, RegistrationCreationService $creation_service, NotificationService $notification_service, Messenger $messenger, MailManager $mail, LanguageManagerInterface $language_manager) {
     $this->request = $request;
     $this->creationService = $creation_service;
     $this->notificationService = $notification_service;
     $this->messenger = $messenger;
     $this->mail = $mail;
+    $this->languageManager = $language_manager;
 
     $request = $this->request->getCurrentRequest();
     $params = $request->attributes->all();
@@ -104,7 +114,8 @@ class ContactForm extends FormBase {
       $container->get('recurring_events_registration.creation_service'),
       $container->get('recurring_events_registration.notification_service'),
       $container->get('messenger'),
-      $container->get('plugin.manager.mail')
+      $container->get('plugin.manager.mail'),
+      $container->get('language_manager')
     );
   }
 
@@ -208,7 +219,7 @@ class ContactForm extends FormBase {
         $params['registrant'] = $registrant;
 
         $to = $registrant->mail->value;
-        $this->mail->mail('recurring_events_registration', 'custom', $to, \Drupal::languageManager()->getDefaultLanguage()->getId(), $params);
+        $this->mail->mail('recurring_events_registration', 'custom', $to, $this->languageManager->getDefaultLanguage()->getId(), $params);
 
         if ($registrant->getWaitlist() == '1') {
           $wait_count++;
diff --git a/modules/recurring_events_registration/src/Form/RegistrantForm.php b/modules/recurring_events_registration/src/Form/RegistrantForm.php
index 18569fcdf3d5dc598ef6c57b9311238f296b9adc..274c158c3a79ad226499eaa69afb0e814634d441 100644
--- a/modules/recurring_events_registration/src/Form/RegistrantForm.php
+++ b/modules/recurring_events_registration/src/Form/RegistrantForm.php
@@ -5,7 +5,7 @@ namespace Drupal\recurring_events_registration\Form;
 use Drupal\Core\Entity\ContentEntityForm;
 use Drupal\Core\Form\FormStateInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
-use Drupal\Core\Entity\EntityManagerInterface;
+use Drupal\Core\Entity\EntityRepositoryInterface;
 use Drupal\Core\Messenger\Messenger;
 use Drupal\recurring_events_registration\RegistrationCreationService;
 use Drupal\Core\Session\AccountProxyInterface;
@@ -75,7 +75,7 @@ class RegistrantForm extends ContentEntityForm {
    */
   public static function create(ContainerInterface $container) {
     return new static(
-      $container->get('entity.manager'),
+      $container->get('entity.repository'),
       $container->get('messenger'),
       $container->get('recurring_events_registration.creation_service'),
       $container->get('current_user'),
@@ -89,8 +89,8 @@ class RegistrantForm extends ContentEntityForm {
   /**
    * Construct an RegistrantForm.
    *
-   * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
-   *   The entity manager service.
+   * @param \Drupal\Core\Entity\EntityRepositoryInterface $entity_repository
+   *   The entity repository service.
    * @param \Drupal\Core\Messenger\Messenger $messenger
    *   The messenger service.
    * @param \Drupal\recurring_events_registration\RegistrationCreationService $creation_service
@@ -107,7 +107,7 @@ class RegistrantForm extends ContentEntityForm {
    *   The entity type manager service.
    */
   public function __construct(
-    EntityManagerInterface $entity_manager,
+    EntityRepositoryInterface $entity_repository,
     Messenger $messenger,
     RegistrationCreationService $creation_service,
     AccountProxyInterface $current_user,
@@ -122,7 +122,7 @@ class RegistrantForm extends ContentEntityForm {
     $this->fieldManager = $field_manager;
     $this->routeMatch = $route_match;
     $this->entityTypeManager = $entity_type_manager;
-    parent::__construct($entity_manager);
+    parent::__construct($entity_repository);
   }
 
   /**
@@ -241,7 +241,9 @@ class RegistrantForm extends ContentEntityForm {
       $form['availability'] = [
         '#type' => 'markup',
         '#prefix' => '<span class="registration-availability">',
-        '#markup' => $this->t('Spaces Available: @availability', ['@availability' => $availability]),
+        '#markup' => $this->t('Spaces Available: @availability', [
+          '@availability' => ($availability == -1) ? $this->t('Unlimited') : $availability,
+        ]),
         '#suffix' => '</span>',
         '#weight' => -99,
       ];
@@ -295,12 +297,11 @@ class RegistrantForm extends ContentEntityForm {
    *   The form state interface.
    */
   protected function hideFormFields(array &$form, FormStateInterface $form_state) {
-    $form_fields = $this->fieldManager->getFieldDefinitions('registrant', 'registrant');
+    $form_fields = $this->fieldManager->getFieldDefinitions('registrant', $this->entity->getBundle());
 
     $availability = $this->creationService->retrieveAvailability();
     $waitlist = $this->creationService->hasWaitlist();
     $registration_open = $this->creationService->registrationIsOpen();
-    $reg_type = $this->creationService->getRegistrationType();
 
     // Prevent the form being displayed if registration is closed, or there are
     // no spaces left, and no waitlist.
@@ -351,7 +352,6 @@ class RegistrantForm extends ContentEntityForm {
       $availability = $this->creationService->retrieveAvailability();
       $waitlist = $this->creationService->hasWaitlist();
       $registration_open = $this->creationService->registrationIsOpen();
-      $reg_type = $this->creationService->getRegistrationType();
 
       $add_to_waitlist = $form_state->getValue('add_to_waitlist');
 
@@ -381,8 +381,6 @@ class RegistrantForm extends ContentEntityForm {
    * {@inheritdoc}
    */
   public function save(array $form, FormStateInterface $form_state) {
-    $entity = $this->entity;
-
     $event_series = $form_state->getTemporaryValue('series');
     // We need to grab a fresh copy of the series to check for updates.
     $event_series = $this->entityTypeManager->getStorage('eventseries')->load($event_series->id());
diff --git a/modules/recurring_events_registration/src/Form/RegistrantResendForm.php b/modules/recurring_events_registration/src/Form/RegistrantResendForm.php
index 734707518a0b01a29a5be37242ede803231d5d82..ddd4a1885f7fe2fa6ab4013bad1934a029d1bf31 100644
--- a/modules/recurring_events_registration/src/Form/RegistrantResendForm.php
+++ b/modules/recurring_events_registration/src/Form/RegistrantResendForm.php
@@ -11,10 +11,10 @@ use Drupal\recurring_events_registration\NotificationService;
 use Drupal\Core\Messenger\Messenger;
 use Drupal\Core\Mail\MailManager;
 use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
-use Drupal\recurring_events\Entity\EventInstance;
 use Drupal\Core\Render\Renderer;
 use Drupal\Core\Link;
 use Drupal\Core\Url;
+use Drupal\Core\Language\LanguageManagerInterface;
 
 /**
  * Provides a form for resending Registrant registration emails.
@@ -79,6 +79,13 @@ class RegistrantResendForm extends FormBase {
    */
   protected $registrant;
 
+  /**
+   * The language manager service.
+   *
+   * @var \Drupal\Core\Language\LanguageManagerInterface
+   */
+  protected $languageManager;
+
   /**
    * Constructs a ContactForm object.
    *
@@ -94,14 +101,17 @@ class RegistrantResendForm extends FormBase {
    *   The mail manager service.
    * @param \Drupal\Core\Render\Renderer $renderer
    *   The renderer service.
+   * @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
+   *   The language manager service.
    */
-  public function __construct(RequestStack $request, RegistrationCreationService $creation_service, NotificationService $notification_service, Messenger $messenger, MailManager $mail, Renderer $renderer) {
+  public function __construct(RequestStack $request, RegistrationCreationService $creation_service, NotificationService $notification_service, Messenger $messenger, MailManager $mail, Renderer $renderer, LanguageManagerInterface $language_manager) {
     $this->request = $request;
     $this->creationService = $creation_service;
     $this->notificationService = $notification_service;
     $this->messenger = $messenger;
     $this->mail = $mail;
     $this->renderer = $renderer;
+    $this->languageManager = $language_manager;
 
     $request = $this->request->getCurrentRequest();
     $params = $request->attributes->all();
@@ -131,7 +141,8 @@ class RegistrantResendForm extends FormBase {
       $container->get('recurring_events_registration.notification_service'),
       $container->get('messenger'),
       $container->get('plugin.manager.mail'),
-      $container->get('renderer')
+      $container->get('renderer'),
+      $container->get('language_manager')
     );
   }
 
@@ -222,7 +233,7 @@ class RegistrantResendForm extends FormBase {
     ];
 
     $to = $this->registrant->mail->value;
-    $this->mail->mail('recurring_events_registration', 'custom', $to, \Drupal::languageManager()->getDefaultLanguage()->getId(), $params);
+    $this->mail->mail('recurring_events_registration', 'custom', $to, $this->languageManager->getDefaultLanguage()->getId(), $params);
     $this->messenger->addMessage($this->t('Registrant email successfully resent.'));
   }
 
diff --git a/modules/recurring_events_registration/src/Form/RegistrantSettingsForm.php b/modules/recurring_events_registration/src/Form/RegistrantSettingsForm.php
index a651023b869bc64b03100c50742e3d1bc1ed9e1e..5add1a1a3cb849b254fd96b652f2dbf5a4985044 100644
--- a/modules/recurring_events_registration/src/Form/RegistrantSettingsForm.php
+++ b/modules/recurring_events_registration/src/Form/RegistrantSettingsForm.php
@@ -9,6 +9,7 @@ use Drupal\Core\Url;
 use Drupal\Core\Link;
 use Drupal\recurring_events_registration\NotificationService;
 use Drupal\recurring_events_registration\RegistrationCreationService;
+use Drupal\Core\Extension\ModuleHandler;
 
 /**
  * Class RegistrantSettingsForm.
@@ -31,6 +32,13 @@ class RegistrantSettingsForm extends ConfigFormBase {
    */
   protected $creationService;
 
+  /**
+   * The module handler service.
+   *
+   * @var \Drupal\Core\Extension\ModuleHandler
+   */
+  protected $moduleHandler;
+
   /**
    * Constructs a RegistrantSettingsForm object.
    *
@@ -38,10 +46,13 @@ class RegistrantSettingsForm extends ConfigFormBase {
    *   The registration notification service.
    * @param \Drupal\recurring_events_registration\RegistrationCreationService $creation_service
    *   The registration creation service.
+   * @param \Drupal\Core\Extension\ModuleHandler $module_handler
+   *   The module handler service.
    */
-  public function __construct(NotificationService $notification_service, RegistrationCreationService $creation_service) {
+  public function __construct(NotificationService $notification_service, RegistrationCreationService $creation_service, ModuleHandler $module_handler) {
     $this->notificationService = $notification_service;
     $this->creationService = $creation_service;
+    $this->moduleHandler = $module_handler;
   }
 
   /**
@@ -50,7 +61,8 @@ class RegistrantSettingsForm extends ConfigFormBase {
   public static function create(ContainerInterface $container) {
     return new static(
       $container->get('recurring_events_registration.notification_service'),
-      $container->get('recurring_events_registration.creation_service')
+      $container->get('recurring_events_registration.creation_service'),
+      $container->get('module_handler')
     );
   }
 
@@ -88,7 +100,7 @@ class RegistrantSettingsForm extends ConfigFormBase {
       ->set('email_notifications', $form_state->getValue('email_notifications'));
 
     $notification_types = [];
-    \Drupal::moduleHandler()->alter('recurring_events_registration_notification_types', $notification_types);
+    $this->moduleHandler->alter('recurring_events_registration_notification_types', $notification_types);
 
     foreach ($notification_types as $type => $notification) {
       $config
@@ -194,7 +206,7 @@ class RegistrantSettingsForm extends ConfigFormBase {
     $tokens = $this->notificationService->getAvailableTokens();
 
     $notification_types = [];
-    \Drupal::moduleHandler()->alter('recurring_events_registration_notification_types', $notification_types);
+    $this->moduleHandler->alter('recurring_events_registration_notification_types', $notification_types);
 
     foreach ($notification_types as $type => $notification) {
       $form['notifications'][$type] = [
diff --git a/modules/recurring_events_registration/src/Form/RegistrantTypeForm.php b/modules/recurring_events_registration/src/Form/RegistrantTypeForm.php
new file mode 100644
index 0000000000000000000000000000000000000000..7d14bd84824627f4a2163d377798435a8ab964eb
--- /dev/null
+++ b/modules/recurring_events_registration/src/Form/RegistrantTypeForm.php
@@ -0,0 +1,97 @@
+<?php
+
+namespace Drupal\recurring_events_registration\Form;
+
+use Drupal\Core\Entity\EntityForm;
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Messenger\Messenger;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * Class RegistrantTypeForm.
+ */
+class RegistrantTypeForm extends EntityForm {
+
+  /**
+   * The messenger service.
+   *
+   * @var \Drupal\Core\Messenger\Messenger
+   */
+  protected $messenger;
+
+  /**
+   * Constructs a RegistrantTypeForm object.
+   *
+   * @param \Drupal\Core\Messenger\Messenger $messenger
+   *   The messenger service.
+   */
+  public function __construct(Messenger $messenger) {
+    $this->messenger = $messenger;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container) {
+    return new static(
+      $container->get('messenger')
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function form(array $form, FormStateInterface $form_state) {
+    $form = parent::form($form, $form_state);
+
+    $registrant_type = $this->entity;
+    $form['label'] = [
+      '#type' => 'textfield',
+      '#title' => $this->t('Label'),
+      '#maxlength' => 255,
+      '#default_value' => $registrant_type->label(),
+      '#description' => $this->t("Label for the registrant type."),
+      '#required' => TRUE,
+    ];
+
+    $form['id'] = [
+      '#type' => 'machine_name',
+      '#default_value' => $registrant_type->id(),
+      '#machine_name' => [
+        'exists' => '\Drupal\recurring_events_registration\Entity\RegistrantType::load',
+      ],
+      '#disabled' => !$registrant_type->isNew(),
+    ];
+
+    $form['description'] = [
+      '#title' => $this->t('Description'),
+      '#type' => 'textarea',
+      '#default_value' => $registrant_type->getDescription(),
+    ];
+
+    return $form;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function save(array $form, FormStateInterface $form_state) {
+    $registrant_type = $this->entity;
+    $status = $registrant_type->save();
+
+    switch ($status) {
+      case SAVED_NEW:
+        $this->messenger->addMessage($this->t('Created the %label registrant type.', [
+          '%label' => $registrant_type->label(),
+        ]));
+        break;
+
+      default:
+        $this->messenger->addMessage($this->t('Saved the %label registrant type.', [
+          '%label' => $registrant_type->label(),
+        ]));
+    }
+    $form_state->setRedirectUrl($registrant_type->toUrl('collection'));
+  }
+
+}
diff --git a/modules/recurring_events_registration/src/Plugin/Field/FieldWidget/EventRegistrationWidget.php b/modules/recurring_events_registration/src/Plugin/Field/FieldWidget/EventRegistrationWidget.php
index 183e036332f57115e317775b4ddc73b5b1a9c5e8..15fcb2540f23bd8b9eb343f7f3f73282bcbd1c12 100644
--- a/modules/recurring_events_registration/src/Plugin/Field/FieldWidget/EventRegistrationWidget.php
+++ b/modules/recurring_events_registration/src/Plugin/Field/FieldWidget/EventRegistrationWidget.php
@@ -5,6 +5,7 @@ namespace Drupal\recurring_events_registration\Plugin\Field\FieldWidget;
 use Drupal\Core\Field\FieldItemListInterface;
 use Drupal\datetime_range\Plugin\Field\FieldWidget\DateRangeDefaultWidget;
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\StringTranslation\StringTranslationTrait;
 
 /**
  * Plugin implementation of the 'event registration' widget.
@@ -19,6 +20,8 @@ use Drupal\Core\Form\FormStateInterface;
  */
 class EventRegistrationWidget extends DateRangeDefaultWidget {
 
+  use StringTranslationTrait;
+
   /**
    * {@inheritdoc}
    */
@@ -29,21 +32,21 @@ class EventRegistrationWidget extends DateRangeDefaultWidget {
 
     $element['registration'] = [
       '#type' => 'checkbox',
-      '#title' => t('Enable Registration'),
-      '#description' => t('Select this box to enable registrations for this event. By doing so you will be able to specify the capacity of the event, and if applicable enable a waitlist.'),
+      '#title' => $this->t('Enable Registration'),
+      '#description' => $this->t('Select this box to enable registrations for this event. By doing so you will be able to specify the capacity of the event, and if applicable enable a waitlist.'),
       '#weight' => 0,
       '#default_value' => $items[$delta]->registration ?: '',
     ];
 
     $element['registration_type'] = [
       '#type' => 'radios',
-      '#title' => t('Registration Type'),
-      '#description' => t('Select whether registrations are for the entire series, or for individual instances.'),
+      '#title' => $this->t('Registration Type'),
+      '#description' => $this->t('Select whether registrations are for the entire series, or for individual instances.'),
       '#weight' => 1,
       '#default_value' => $items[$delta]->registration_type ?: 'instance',
       '#options' => [
-        'instance' => t('Individual Event Registration'),
-        'series' => t('Entire Series Registration'),
+        'instance' => $this->t('Individual Event Registration'),
+        'series' => $this->t('Entire Series Registration'),
       ],
       '#states' => [
         'visible' => [
@@ -54,13 +57,13 @@ class EventRegistrationWidget extends DateRangeDefaultWidget {
 
     $element['registration_dates'] = [
       '#type' => 'radios',
-      '#title' => t('Registration Dates'),
-      '#description' => t('Choose between open or scheduled registration.'),
+      '#title' => $this->t('Registration Dates'),
+      '#description' => $this->t('Choose between open or scheduled registration.'),
       '#weight' => 2,
       '#default_value' => $items[$delta]->registration_dates ?: 'open',
       '#options' => [
-        'open' => t('Open Registration'),
-        'scheduled' => t('Scheduled Registration'),
+        'open' => $this->t('Open Registration'),
+        'scheduled' => $this->t('Scheduled Registration'),
       ],
       '#states' => [
         'visible' => [
@@ -71,7 +74,7 @@ class EventRegistrationWidget extends DateRangeDefaultWidget {
 
     $element['series_registration'] = [
       '#type' => 'fieldset',
-      '#title' => t('Series Registration'),
+      '#title' => $this->t('Series Registration'),
       '#weight' => 3,
       '#states' => [
         'visible' => [
@@ -87,12 +90,12 @@ class EventRegistrationWidget extends DateRangeDefaultWidget {
     unset($element['value']);
     unset($element['end_value']);
 
-    $element['series_registration']['value']['#title'] = t('Registration Opens');
-    $element['series_registration']['end_value']['#title'] = t('Registration Closes');
+    $element['series_registration']['value']['#title'] = $this->t('Registration Opens');
+    $element['series_registration']['end_value']['#title'] = $this->t('Registration Closes');
 
     $element['instance_registration'] = [
       '#type' => 'fieldset',
-      '#title' => t('Instance Registration'),
+      '#title' => $this->t('Instance Registration'),
       '#weight' => 3,
       '#states' => [
         'visible' => [
@@ -105,8 +108,8 @@ class EventRegistrationWidget extends DateRangeDefaultWidget {
 
     $element['instance_registration']['time_amount'] = [
       '#type' => 'number',
-      '#title' => t('Registration Time Amount'),
-      '#description' => t('Enter the amount of time in days or hours before the event(s) start time(s) that registration should open.'),
+      '#title' => $this->t('Registration Time Amount'),
+      '#description' => $this->t('Enter the amount of time in days or hours before the event(s) start time(s) that registration should open.'),
       '#weight' => 0,
       '#default_value' => $items[$delta]->time_amount ?: '',
       '#min' => 0,
@@ -114,20 +117,20 @@ class EventRegistrationWidget extends DateRangeDefaultWidget {
 
     $element['instance_registration']['time_type'] = [
       '#type' => 'select',
-      '#title' => t('Registration Time Type'),
-      '#description' => t("Select either Days or Hours to choose how long before which an event's registration will open."),
+      '#title' => $this->t('Registration Time Type'),
+      '#description' => $this->t("Select either Days or Hours to choose how long before which an event's registration will open."),
       '#weight' => 1,
       '#default_value' => $items[$delta]->time_type ?: '',
       '#options' => [
-        'days' => t('Days'),
-        'hours' => t('Hours'),
+        'days' => $this->t('Days'),
+        'hours' => $this->t('Hours'),
       ],
     ];
 
     $element['capacity'] = [
       '#type' => 'number',
-      '#title' => t('Total Number of Spaces Available'),
-      '#description' => t('Maximum number of attendees available for each series, or individual event.'),
+      '#title' => $this->t('Total Number of Spaces Available'),
+      '#description' => $this->t('Maximum number of attendees available for each series, or individual event. Leave blank for unlimited.'),
       '#weight' => 4,
       '#default_value' => $items[$delta]->capacity ?: '',
       '#min' => 0,
@@ -140,8 +143,8 @@ class EventRegistrationWidget extends DateRangeDefaultWidget {
 
     $element['waitlist'] = [
       '#type' => 'checkbox',
-      '#title' => t('Enable Waiting List'),
-      '#description' => t('Enable a waiting list if the number of registrations reaches capacity.'),
+      '#title' => $this->t('Enable Waiting List'),
+      '#description' => $this->t('Enable a waiting list if the number of registrations reaches capacity.'),
       '#weight' => 5,
       '#default_value' => $items[$delta]->waitlist ?: '',
       '#states' => [
diff --git a/modules/recurring_events_registration/src/Plugin/views/access/EventRegistrationListAccess.php b/modules/recurring_events_registration/src/Plugin/views/access/EventRegistrationListAccess.php
new file mode 100644
index 0000000000000000000000000000000000000000..2bfc1d48a0db1f8a0a766498a30bd745717c4ca7
--- /dev/null
+++ b/modules/recurring_events_registration/src/Plugin/views/access/EventRegistrationListAccess.php
@@ -0,0 +1,81 @@
+<?php
+
+namespace Drupal\recurring_events_registration\Plugin\views\access;
+
+use Drupal\views\Plugin\views\access\AccessPluginBase;
+use Drupal\Core\Session\AccountInterface;
+use Symfony\Component\Routing\Route;
+use Drupal\recurring_events_registration\AccessHandler;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * Custom access plugin for Event Registration views.
+ *
+ * @ingroup views_access_plugins
+ *
+ * @ViewsAccess(
+ *   id = "event_registration_list_access",
+ *   title = @Translation("View Event Registration List"),
+ *   help = @Translation("Access will be granted depending on the registration configuration of an event.")
+ * )
+ */
+class EventRegistrationListAccess extends AccessPluginBase {
+
+  /**
+   * The access handler.
+   *
+   * @var \Drupal\recurring_events_registration\AccessHandler
+   */
+  protected $accessHandler;
+
+  /**
+   * Constructs an EventRegistrationListAccess object.
+   *
+   * @param array $configuration
+   *   A configuration array containing information about the plugin instance.
+   * @param string $plugin_id
+   *   The plugin_id for the plugin instance.
+   * @param mixed $plugin_definition
+   *   The plugin implementation definition.
+   * @param Drupal\recurring_events_registration\AccessHandler $access_handler
+   *   The access handler.
+   */
+  public function __construct(array $configuration, $plugin_id, $plugin_definition, AccessHandler $access_handler) {
+    parent::__construct($configuration, $plugin_id, $plugin_definition);
+    $this->accessHandler = $access_handler;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
+    return new static(
+      $configuration,
+      $plugin_id,
+      $plugin_definition,
+      $container->get('recurring_events_registration.access_handler')
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function summaryTitle() {
+    return $this->t('Event Registration Access');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function access(AccountInterface $account) {
+    return $this->accessHandler->eventHasRegistration() && $this->accessHandler->userHasPermission($account);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function alterRouteDefinition(Route $route) {
+    $route->setRequirement('_custom_access', 'recurring_events_registration.access_handler::eventRegistrationListAccess');
+  }
+
+}
diff --git a/modules/recurring_events_registration/src/RegistrantAccessControlHandler.php b/modules/recurring_events_registration/src/RegistrantAccessControlHandler.php
index f1d814a684a193e2f10624fef4616cc2fb08d50b..3d58f29c721f7c5bcc8d06ad4253c2f3601bef8f 100644
--- a/modules/recurring_events_registration/src/RegistrantAccessControlHandler.php
+++ b/modules/recurring_events_registration/src/RegistrantAccessControlHandler.php
@@ -10,6 +10,7 @@ use Drupal\Component\Uuid\Uuid;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Entity\EntityHandlerInterface;
+use Drupal\Core\Entity\EntityTypeManagerInterface;
 
 /**
  * Access controller for the Registrant entity.
@@ -25,6 +26,13 @@ class RegistrantAccessControlHandler extends EntityAccessControlHandler implemen
    */
   protected $creationService;
 
+  /**
+   * The entity type manager service.
+   *
+   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
+   */
+  protected $entityTypeManager;
+
   /**
    * RegistrantAccessControlHandler constructor.
    *
@@ -32,10 +40,13 @@ class RegistrantAccessControlHandler extends EntityAccessControlHandler implemen
    *   The entity type.
    * @param \Drupal\recurring_events_registration\RegistrationCreationService $creation_service
    *   The creation service.
+   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
+   *   The entity type manager service.
    */
-  public function __construct(EntityTypeInterface $entity_type, RegistrationCreationService $creation_service) {
+  public function __construct(EntityTypeInterface $entity_type, RegistrationCreationService $creation_service, EntityTypeManagerInterface $entity_type_manager) {
     parent::__construct($entity_type);
     $this->creationService = $creation_service;
+    $this->entityTypeManager = $entity_type_manager;
   }
 
   /**
@@ -44,7 +55,8 @@ class RegistrantAccessControlHandler extends EntityAccessControlHandler implemen
   public static function createInstance(ContainerInterface $container, EntityTypeInterface $entity_type) {
     return new static(
       $entity_type,
-      $container->get('recurring_events_registration.creation_service')
+      $container->get('recurring_events_registration.creation_service'),
+      $container->get('entity_type.manager')
     );
   }
 
@@ -87,6 +99,9 @@ class RegistrantAccessControlHandler extends EntityAccessControlHandler implemen
   protected function checkCreateAccess(AccountInterface $account, array $context, $entity_bundle = NULL) {
     $params = \Drupal::request()->attributes->all();
     if (!empty($params['eventinstance'])) {
+      if (is_string($params['eventinstance']) || is_numeric($params['eventinstance'])) {
+        $params['eventinstance'] = $this->entityTypeManager->getStorage('eventinstance')->load($params['eventinstance']);
+      }
       $this->creationService->setEventInstance($params['eventinstance']);
       if ($this->creationService->hasRegistration()) {
         return AccessResult::allowedIfHasPermission($account, 'add registrant entities');
diff --git a/modules/recurring_events_registration/src/RegistrantListBuilder.php b/modules/recurring_events_registration/src/RegistrantListBuilder.php
index 7d12a9c50f1044d62565f499c53a982350715cc1..5d0fdb4f71476b97b3ea713f7c68ecf6a44e00eb 100644
--- a/modules/recurring_events_registration/src/RegistrantListBuilder.php
+++ b/modules/recurring_events_registration/src/RegistrantListBuilder.php
@@ -113,7 +113,7 @@ class RegistrantListBuilder extends EntityListBuilder {
 
     $row['id'] = $entity->id();
     $row['series'] = $series->toLink($series->title->value);
-    $timezone = new \DateTimeZone(drupal_get_user_timezone());
+    $timezone = new \DateTimeZone(date_default_timezone_get());
     $date = $instance->date->start_date;
     $date->setTimezone($timezone);
     $row['instance'] = $instance->toLink($date->format($this->config->get('recurring_events_registration.registrant.config')->get('date_format')));
diff --git a/modules/recurring_events_registration/src/RegistrantTypeHtmlRouteProvider.php b/modules/recurring_events_registration/src/RegistrantTypeHtmlRouteProvider.php
new file mode 100644
index 0000000000000000000000000000000000000000..899a5c071b4dfb1b21eeb3be5d8eb17f1aedae55
--- /dev/null
+++ b/modules/recurring_events_registration/src/RegistrantTypeHtmlRouteProvider.php
@@ -0,0 +1,24 @@
+<?php
+
+namespace Drupal\recurring_events_registration;
+
+use Drupal\Core\Entity\EntityTypeInterface;
+use Drupal\Core\Entity\Routing\AdminHtmlRouteProvider;
+
+/**
+ * Provides routes for Registrant type entities.
+ *
+ * @see Drupal\Core\Entity\Routing\AdminHtmlRouteProvider
+ * @see Drupal\Core\Entity\Routing\DefaultHtmlRouteProvider
+ */
+class RegistrantTypeHtmlRouteProvider extends AdminHtmlRouteProvider {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getRoutes(EntityTypeInterface $entity_type) {
+    $collection = parent::getRoutes($entity_type);
+    return $collection;
+  }
+
+}
diff --git a/modules/recurring_events_registration/src/RegistrantTypeListBuilder.php b/modules/recurring_events_registration/src/RegistrantTypeListBuilder.php
new file mode 100644
index 0000000000000000000000000000000000000000..fb31d343f39abedddaa95b44c7044a15f02c2017
--- /dev/null
+++ b/modules/recurring_events_registration/src/RegistrantTypeListBuilder.php
@@ -0,0 +1,45 @@
+<?php
+
+namespace Drupal\recurring_events_registration;
+
+use Drupal\Core\Config\Entity\ConfigEntityListBuilder;
+use Drupal\Core\Entity\EntityInterface;
+
+/**
+ * Provides a listing of Registrant type entities.
+ */
+class RegistrantTypeListBuilder extends ConfigEntityListBuilder {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function buildHeader() {
+    $header['label'] = $this->t('Registrant type');
+    $header['id'] = $this->t('Machine name');
+    return $header + parent::buildHeader();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getDefaultOperations(EntityInterface $entity) {
+    $operations = parent::getDefaultOperations($entity);
+    // Place the edit operation after the operations added by field_ui.module
+    // which have the weights 15, 20, 25.
+    if (isset($operations['edit'])) {
+      $operations['edit']['weight'] = 30;
+    }
+    return $operations;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function buildRow(EntityInterface $entity) {
+    $row['label'] = $entity->label();
+    $row['id'] = $entity->id();
+    // You probably want a few more properties here...
+    return $row + parent::buildRow($entity);
+  }
+
+}
diff --git a/modules/recurring_events_registration/src/RegistrationCreationService.php b/modules/recurring_events_registration/src/RegistrationCreationService.php
index 6451c48830ff249c72f42e2b09bbafabc56b920a..c2f3e017284f756658b9d82018058141b57271f8 100644
--- a/modules/recurring_events_registration/src/RegistrationCreationService.php
+++ b/modules/recurring_events_registration/src/RegistrationCreationService.php
@@ -227,7 +227,8 @@ class RegistrationCreationService {
 
     $capacity = $this->eventSeries->event_registration->capacity;
     if (empty($capacity)) {
-      $capacity = 0;
+      // Set capacity to unlimited if no capacity is specified.
+      return -1;
     }
     $availability = $capacity - count($parties);
     if ($availability < 0) {
@@ -292,8 +293,6 @@ class RegistrationCreationService {
    *   Whether this user has already registered for this event.
    */
   public function hasUserRegisteredById($uid) {
-    $properties = [];
-
     $registrants = $this->retrieveRegisteredParties(TRUE, TRUE, $uid);
     return !empty($registrants);
   }
@@ -323,7 +322,7 @@ class RegistrationCreationService {
     $waitlisted_users = $this->retrieveWaitlistedParties();
     if (!empty($waitlisted_users)) {
       $first = reset($waitlisted_users);
-      \Drupal::moduleHandler()->alter('recurring_events_registration_first_waitlist', $first);
+      $this->moduleHandler->alter('recurring_events_registration_first_waitlist', $first);
       return $first;
     }
     return NULL;
@@ -431,7 +430,7 @@ class RegistrationCreationService {
       $reg_type = $this->getRegistrationType();
       $reg_dates_type = $this->getRegistrationDatesType();
 
-      $timezone = new \DateTimeZone(drupal_get_user_timezone());
+      $timezone = new \DateTimeZone(date_default_timezone_get());
       $utc_timezone = new \DateTimeZone(DateTimeItemInterface::STORAGE_TIMEZONE);
 
       $now = new DrupalDateTime();
diff --git a/modules/recurring_events_views/README.md b/modules/recurring_events_views/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..cb9113f340b5532ad3ea0dac13c28193cbbcf838
--- /dev/null
+++ b/modules/recurring_events_views/README.md
@@ -0,0 +1,28 @@
+# Recurring Events Views (recurring_events_views)
+---
+
+## Introduction
+Recurring Events  provides listings for event series, event instances and
+registrations. For many installations this will provide a satisfactory way of
+managing events without the need to install extra modules.
+
+For those cases which call for something more flexible, views integration is
+provided by an optional sub-module called Recurring Events Views
+(recurring_events_views).
+
+After enabling this submodule, all listings are replaced by views and no further
+configuration is necessary.
+
+### Views are provided for;
+
+- Event Series
+- Event Instances
+- Registrations
+
+Admin views are available to user roles with suitable permissions. There are
+also views for anonymous and authenticated users, for the front end.
+
+- Admin views are provided with sensible default settings and exposed filters.
+- The front end event series listings, display only future or current events.
+
+The default views can be further customized as needed.
diff --git a/modules/recurring_events_views/config/install/views.view.event_series.yml b/modules/recurring_events_views/config/install/views.view.event_series.yml
new file mode 100644
index 0000000000000000000000000000000000000000..13c81fdac0e9038e66afc34058891ab31bbc8824
--- /dev/null
+++ b/modules/recurring_events_views/config/install/views.view.event_series.yml
@@ -0,0 +1,1426 @@
+langcode: en
+status: true
+dependencies:
+  config:
+    - core.entity_view_mode.eventseries.list
+    - system.menu.main
+  module:
+    - options
+    - recurring_events
+    - user
+id: event_series
+label: 'Event Series'
+module: views
+description: 'A view showing all the event series on the site.'
+tag: ''
+base_table: eventseries_field_data
+base_field: id
+display:
+  default:
+    display_plugin: default
+    id: default
+    display_title: Master
+    position: 0
+    display_options:
+      access:
+        type: perm
+        options:
+          perm: 'view eventseries entity'
+      cache:
+        type: tag
+        options: {  }
+      query:
+        type: views_query
+        options:
+          disable_sql_rewrite: false
+          distinct: false
+          replica: false
+          query_comment: ''
+          query_tags: {  }
+      exposed_form:
+        type: basic
+        options:
+          submit_button: Apply
+          reset_button: false
+          reset_button_label: Reset
+          exposed_sorts_label: 'Sort by'
+          expose_sort_order: true
+          sort_asc_label: Asc
+          sort_desc_label: Desc
+      pager:
+        type: full
+        options:
+          items_per_page: 10
+          offset: 0
+          id: 0
+          total_pages: null
+          tags:
+            previous: ‹‹
+            next: ››
+            first: '« First'
+            last: 'Last »'
+          expose:
+            items_per_page: false
+            items_per_page_label: 'Items per page'
+            items_per_page_options: '5, 10, 25, 50'
+            items_per_page_options_all: false
+            items_per_page_options_all_label: '- All -'
+            offset: false
+            offset_label: Offset
+          quantity: 9
+      style:
+        type: table
+      row:
+        type: fields
+      fields:
+        title:
+          id: title
+          table: eventseries_field_data
+          field: title
+          relationship: none
+          group_type: group
+          admin_label: ''
+          label: Title
+          exclude: false
+          alter:
+            alter_text: false
+            text: ''
+            make_link: false
+            path: ''
+            absolute: false
+            external: false
+            replace_spaces: false
+            path_case: none
+            trim_whitespace: false
+            alt: ''
+            rel: ''
+            link_class: ''
+            prefix: ''
+            suffix: ''
+            target: ''
+            nl2br: false
+            max_length: 0
+            word_boundary: true
+            ellipsis: true
+            more_link: false
+            more_link_text: ''
+            more_link_path: ''
+            strip_tags: false
+            trim: false
+            preserve_tags: ''
+            html: false
+          element_type: ''
+          element_class: ''
+          element_label_type: ''
+          element_label_class: ''
+          element_label_colon: true
+          element_wrapper_type: ''
+          element_wrapper_class: ''
+          element_default_classes: true
+          empty: ''
+          hide_empty: false
+          empty_zero: false
+          hide_alter_empty: true
+          click_sort_column: value
+          type: string
+          settings:
+            link_to_entity: true
+          group_column: value
+          group_columns: {  }
+          group_rows: true
+          delta_limit: 0
+          delta_offset: 0
+          delta_reversed: false
+          delta_first_last: false
+          multi_type: separator
+          separator: ', '
+          field_api_classes: false
+          entity_type: null
+          entity_field: title
+          plugin_id: field
+        type:
+          id: type
+          table: eventseries_field_data
+          field: type
+          relationship: none
+          group_type: group
+          admin_label: ''
+          label: Type
+          exclude: false
+          alter:
+            alter_text: false
+            text: ''
+            make_link: false
+            path: ''
+            absolute: false
+            external: false
+            replace_spaces: false
+            path_case: none
+            trim_whitespace: false
+            alt: ''
+            rel: ''
+            link_class: ''
+            prefix: ''
+            suffix: ''
+            target: ''
+            nl2br: false
+            max_length: 0
+            word_boundary: true
+            ellipsis: true
+            more_link: false
+            more_link_text: ''
+            more_link_path: ''
+            strip_tags: false
+            trim: false
+            preserve_tags: ''
+            html: false
+          element_type: ''
+          element_class: ''
+          element_label_type: ''
+          element_label_class: ''
+          element_label_colon: true
+          element_wrapper_type: ''
+          element_wrapper_class: ''
+          element_default_classes: true
+          empty: ''
+          hide_empty: false
+          empty_zero: false
+          hide_alter_empty: true
+          click_sort_column: target_id
+          type: entity_reference_label
+          settings:
+            link: false
+          group_column: target_id
+          group_columns: {  }
+          group_rows: true
+          delta_limit: 0
+          delta_offset: 0
+          delta_reversed: false
+          delta_first_last: false
+          multi_type: separator
+          separator: ', '
+          field_api_classes: false
+          entity_type: eventseries
+          entity_field: type
+          plugin_id: field
+        recur_type:
+          id: recur_type
+          table: eventseries_field_data
+          field: recur_type
+          relationship: none
+          group_type: group
+          admin_label: ''
+          label: 'Recur Type'
+          exclude: false
+          alter:
+            alter_text: false
+            text: ''
+            make_link: false
+            path: ''
+            absolute: false
+            external: false
+            replace_spaces: false
+            path_case: none
+            trim_whitespace: false
+            alt: ''
+            rel: ''
+            link_class: ''
+            prefix: ''
+            suffix: ''
+            target: ''
+            nl2br: false
+            max_length: 0
+            word_boundary: true
+            ellipsis: true
+            more_link: false
+            more_link_text: ''
+            more_link_path: ''
+            strip_tags: false
+            trim: false
+            preserve_tags: ''
+            html: false
+          element_type: ''
+          element_class: ''
+          element_label_type: ''
+          element_label_class: ''
+          element_label_colon: true
+          element_wrapper_type: ''
+          element_wrapper_class: ''
+          element_default_classes: true
+          empty: ''
+          hide_empty: false
+          empty_zero: false
+          hide_alter_empty: true
+          click_sort_column: value
+          type: list_default
+          settings: {  }
+          group_column: value
+          group_columns: {  }
+          group_rows: true
+          delta_limit: 0
+          delta_offset: 0
+          delta_reversed: false
+          delta_first_last: false
+          multi_type: separator
+          separator: ', '
+          field_api_classes: false
+          entity_type: eventseries
+          entity_field: recur_type
+          plugin_id: field
+        eventseries_instance_count:
+          id: eventseries_instance_count
+          table: eventseries_field_data
+          field: eventseries_instance_count
+          relationship: none
+          group_type: group
+          admin_label: ''
+          label: Instances
+          exclude: false
+          alter:
+            alter_text: false
+            text: ''
+            make_link: false
+            path: ''
+            absolute: false
+            external: false
+            replace_spaces: false
+            path_case: none
+            trim_whitespace: false
+            alt: ''
+            rel: ''
+            link_class: ''
+            prefix: ''
+            suffix: ''
+            target: ''
+            nl2br: false
+            max_length: 0
+            word_boundary: true
+            ellipsis: true
+            more_link: false
+            more_link_text: ''
+            more_link_path: ''
+            strip_tags: false
+            trim: false
+            preserve_tags: ''
+            html: false
+          element_type: ''
+          element_class: ''
+          element_label_type: ''
+          element_label_class: ''
+          element_label_colon: true
+          element_wrapper_type: ''
+          element_wrapper_class: ''
+          element_default_classes: true
+          empty: ''
+          hide_empty: false
+          empty_zero: false
+          hide_alter_empty: true
+          entity_type: eventseries
+          plugin_id: eventseries_instance_count
+        eventseries_start_date:
+          id: eventseries_start_date
+          table: eventseries_field_data
+          field: eventseries_start_date
+          relationship: none
+          group_type: group
+          admin_label: ''
+          label: 'Series Starts'
+          exclude: false
+          alter:
+            alter_text: false
+            text: ''
+            make_link: false
+            path: ''
+            absolute: false
+            external: false
+            replace_spaces: false
+            path_case: none
+            trim_whitespace: false
+            alt: ''
+            rel: ''
+            link_class: ''
+            prefix: ''
+            suffix: ''
+            target: ''
+            nl2br: false
+            max_length: 0
+            word_boundary: true
+            ellipsis: true
+            more_link: false
+            more_link_text: ''
+            more_link_path: ''
+            strip_tags: false
+            trim: false
+            preserve_tags: ''
+            html: false
+          element_type: ''
+          element_class: ''
+          element_label_type: ''
+          element_label_class: ''
+          element_label_colon: true
+          element_wrapper_type: ''
+          element_wrapper_class: ''
+          element_default_classes: true
+          empty: ''
+          hide_empty: false
+          empty_zero: false
+          hide_alter_empty: true
+          entity_type: eventseries
+          plugin_id: eventseries_start_date
+        uid:
+          id: uid
+          table: eventseries_field_data
+          field: uid
+          relationship: none
+          group_type: group
+          admin_label: ''
+          label: Author
+          exclude: false
+          alter:
+            alter_text: false
+            text: ''
+            make_link: false
+            path: ''
+            absolute: false
+            external: false
+            replace_spaces: false
+            path_case: none
+            trim_whitespace: false
+            alt: ''
+            rel: ''
+            link_class: ''
+            prefix: ''
+            suffix: ''
+            target: ''
+            nl2br: false
+            max_length: 0
+            word_boundary: true
+            ellipsis: true
+            more_link: false
+            more_link_text: ''
+            more_link_path: ''
+            strip_tags: false
+            trim: false
+            preserve_tags: ''
+            html: false
+          element_type: ''
+          element_class: ''
+          element_label_type: ''
+          element_label_class: ''
+          element_label_colon: true
+          element_wrapper_type: ''
+          element_wrapper_class: ''
+          element_default_classes: true
+          empty: ''
+          hide_empty: false
+          empty_zero: false
+          hide_alter_empty: true
+          click_sort_column: target_id
+          type: entity_reference_label
+          settings:
+            link: true
+          group_column: target_id
+          group_columns: {  }
+          group_rows: true
+          delta_limit: 0
+          delta_offset: 0
+          delta_reversed: false
+          delta_first_last: false
+          multi_type: separator
+          separator: ', '
+          field_api_classes: false
+          entity_type: eventseries
+          entity_field: uid
+          plugin_id: field
+        status:
+          id: status
+          table: eventseries_field_data
+          field: status
+          relationship: none
+          group_type: group
+          admin_label: ''
+          label: Published
+          exclude: false
+          alter:
+            alter_text: false
+            text: ''
+            make_link: false
+            path: ''
+            absolute: false
+            external: false
+            replace_spaces: false
+            path_case: none
+            trim_whitespace: false
+            alt: ''
+            rel: ''
+            link_class: ''
+            prefix: ''
+            suffix: ''
+            target: ''
+            nl2br: false
+            max_length: 0
+            word_boundary: true
+            ellipsis: true
+            more_link: false
+            more_link_text: ''
+            more_link_path: ''
+            strip_tags: false
+            trim: false
+            preserve_tags: ''
+            html: false
+          element_type: ''
+          element_class: ''
+          element_label_type: ''
+          element_label_class: ''
+          element_label_colon: true
+          element_wrapper_type: ''
+          element_wrapper_class: ''
+          element_default_classes: true
+          empty: ''
+          hide_empty: false
+          empty_zero: false
+          hide_alter_empty: true
+          click_sort_column: value
+          type: boolean
+          settings:
+            format: yes-no
+            format_custom_true: ''
+            format_custom_false: ''
+          group_column: value
+          group_columns: {  }
+          group_rows: true
+          delta_limit: 0
+          delta_offset: 0
+          delta_reversed: false
+          delta_first_last: false
+          multi_type: separator
+          separator: ', '
+          field_api_classes: false
+          entity_type: eventseries
+          entity_field: status
+          plugin_id: field
+        created:
+          id: created
+          table: eventseries_field_data
+          field: created
+          relationship: none
+          group_type: group
+          admin_label: ''
+          label: Created
+          exclude: false
+          alter:
+            alter_text: false
+            text: ''
+            make_link: false
+            path: ''
+            absolute: false
+            external: false
+            replace_spaces: false
+            path_case: none
+            trim_whitespace: false
+            alt: ''
+            rel: ''
+            link_class: ''
+            prefix: ''
+            suffix: ''
+            target: ''
+            nl2br: false
+            max_length: 0
+            word_boundary: true
+            ellipsis: true
+            more_link: false
+            more_link_text: ''
+            more_link_path: ''
+            strip_tags: false
+            trim: false
+            preserve_tags: ''
+            html: false
+          element_type: ''
+          element_class: ''
+          element_label_type: ''
+          element_label_class: ''
+          element_label_colon: true
+          element_wrapper_type: ''
+          element_wrapper_class: ''
+          element_default_classes: true
+          empty: ''
+          hide_empty: false
+          empty_zero: false
+          hide_alter_empty: true
+          click_sort_column: value
+          type: timestamp
+          settings:
+            date_format: medium
+            custom_date_format: ''
+            timezone: ''
+          group_column: value
+          group_columns: {  }
+          group_rows: true
+          delta_limit: 0
+          delta_offset: 0
+          delta_reversed: false
+          delta_first_last: false
+          multi_type: separator
+          separator: ', '
+          field_api_classes: false
+          entity_type: eventseries
+          entity_field: created
+          plugin_id: field
+        changed:
+          id: changed
+          table: eventseries_field_data
+          field: changed
+          relationship: none
+          group_type: group
+          admin_label: ''
+          label: Changed
+          exclude: false
+          alter:
+            alter_text: false
+            text: ''
+            make_link: false
+            path: ''
+            absolute: false
+            external: false
+            replace_spaces: false
+            path_case: none
+            trim_whitespace: false
+            alt: ''
+            rel: ''
+            link_class: ''
+            prefix: ''
+            suffix: ''
+            target: ''
+            nl2br: false
+            max_length: 0
+            word_boundary: true
+            ellipsis: true
+            more_link: false
+            more_link_text: ''
+            more_link_path: ''
+            strip_tags: false
+            trim: false
+            preserve_tags: ''
+            html: false
+          element_type: ''
+          element_class: ''
+          element_label_type: ''
+          element_label_class: ''
+          element_label_colon: true
+          element_wrapper_type: ''
+          element_wrapper_class: ''
+          element_default_classes: true
+          empty: ''
+          hide_empty: false
+          empty_zero: false
+          hide_alter_empty: true
+          click_sort_column: value
+          type: timestamp
+          settings:
+            date_format: medium
+            custom_date_format: ''
+            timezone: ''
+          group_column: value
+          group_columns: {  }
+          group_rows: true
+          delta_limit: 0
+          delta_offset: 0
+          delta_reversed: false
+          delta_first_last: false
+          multi_type: separator
+          separator: ', '
+          field_api_classes: false
+          entity_type: eventseries
+          entity_field: changed
+          plugin_id: field
+        operations:
+          id: operations
+          table: eventseries
+          field: operations
+          relationship: none
+          group_type: group
+          admin_label: ''
+          label: Operations
+          exclude: false
+          alter:
+            alter_text: false
+            text: ''
+            make_link: false
+            path: ''
+            absolute: false
+            external: false
+            replace_spaces: false
+            path_case: none
+            trim_whitespace: false
+            alt: ''
+            rel: ''
+            link_class: ''
+            prefix: ''
+            suffix: ''
+            target: ''
+            nl2br: false
+            max_length: 0
+            word_boundary: true
+            ellipsis: true
+            more_link: false
+            more_link_text: ''
+            more_link_path: ''
+            strip_tags: false
+            trim: false
+            preserve_tags: ''
+            html: false
+          element_type: ''
+          element_class: ''
+          element_label_type: ''
+          element_label_class: ''
+          element_label_colon: true
+          element_wrapper_type: ''
+          element_wrapper_class: ''
+          element_default_classes: true
+          empty: ''
+          hide_empty: false
+          empty_zero: false
+          hide_alter_empty: true
+          destination: false
+          entity_type: eventseries
+          plugin_id: entity_operations
+      filters:
+        title:
+          id: title
+          table: eventseries_field_data
+          field: title
+          relationship: none
+          group_type: group
+          admin_label: ''
+          operator: contains
+          value: ''
+          group: 1
+          exposed: true
+          expose:
+            operator_id: title_op
+            label: Title
+            description: ''
+            use_operator: false
+            operator: title_op
+            identifier: title
+            required: false
+            remember: false
+            multiple: false
+            remember_roles:
+              authenticated: authenticated
+              anonymous: '0'
+              administrator: '0'
+            placeholder: ''
+            operator_limit_selection: false
+            operator_list: {  }
+          is_grouped: false
+          group_info:
+            label: ''
+            description: ''
+            identifier: ''
+            optional: true
+            widget: select
+            multiple: false
+            remember: false
+            default_group: All
+            default_group_multiple: {  }
+            group_items: {  }
+          entity_type: eventseries
+          entity_field: title
+          plugin_id: string
+        type:
+          id: type
+          table: eventseries_field_data
+          field: type
+          relationship: none
+          group_type: group
+          admin_label: ''
+          operator: in
+          value: {  }
+          group: 1
+          exposed: true
+          expose:
+            operator_id: type_op
+            label: Type
+            description: ''
+            use_operator: false
+            operator: type_op
+            identifier: type
+            required: false
+            remember: false
+            multiple: false
+            remember_roles:
+              authenticated: authenticated
+              anonymous: '0'
+              administrator: '0'
+            reduce: false
+            operator_limit_selection: false
+            operator_list: {  }
+          is_grouped: false
+          group_info:
+            label: ''
+            description: ''
+            identifier: ''
+            optional: true
+            widget: select
+            multiple: false
+            remember: false
+            default_group: All
+            default_group_multiple: {  }
+            group_items: {  }
+          entity_type: eventseries
+          entity_field: type
+          plugin_id: bundle
+        recur_type:
+          id: recur_type
+          table: eventseries_field_data
+          field: recur_type
+          relationship: none
+          group_type: group
+          admin_label: ''
+          operator: contains
+          value: ''
+          group: 1
+          exposed: true
+          expose:
+            operator_id: recur_type_op
+            label: 'Recur Type'
+            description: ''
+            use_operator: false
+            operator: recur_type_op
+            identifier: recur_type
+            required: false
+            remember: false
+            multiple: false
+            remember_roles:
+              authenticated: authenticated
+              anonymous: '0'
+              administrator: '0'
+            placeholder: ''
+            operator_limit_selection: false
+            operator_list: {  }
+          is_grouped: false
+          group_info:
+            label: ''
+            description: ''
+            identifier: ''
+            optional: true
+            widget: select
+            multiple: false
+            remember: false
+            default_group: All
+            default_group_multiple: {  }
+            group_items: {  }
+          entity_type: eventseries
+          entity_field: recur_type
+          plugin_id: string
+        uid:
+          id: uid
+          table: users_field_data
+          field: uid
+          relationship: uid
+          group_type: group
+          admin_label: ''
+          operator: in
+          value: {  }
+          group: 1
+          exposed: true
+          expose:
+            operator_id: uid_op
+            label: Author
+            description: ''
+            use_operator: false
+            operator: uid_op
+            identifier: uid
+            required: false
+            remember: false
+            multiple: false
+            remember_roles:
+              authenticated: authenticated
+              anonymous: '0'
+              administrator: '0'
+            reduce: false
+            operator_limit_selection: false
+            operator_list: {  }
+          is_grouped: false
+          group_info:
+            label: ''
+            description: ''
+            identifier: ''
+            optional: true
+            widget: select
+            multiple: false
+            remember: false
+            default_group: All
+            default_group_multiple: {  }
+            group_items: {  }
+          entity_type: user
+          entity_field: uid
+          plugin_id: user_name
+        created:
+          id: created
+          table: eventseries_field_data
+          field: created
+          relationship: none
+          group_type: group
+          admin_label: ''
+          operator: '>='
+          value:
+            min: ''
+            max: ''
+            value: ''
+            type: date
+          group: 1
+          exposed: true
+          expose:
+            operator_id: created_op
+            label: 'Created After'
+            description: ''
+            use_operator: false
+            operator: created_op
+            identifier: created
+            required: false
+            remember: false
+            multiple: false
+            remember_roles:
+              authenticated: authenticated
+              anonymous: '0'
+              administrator: '0'
+            placeholder: ''
+            min_placeholder: ''
+            max_placeholder: ''
+            operator_limit_selection: false
+            operator_list: {  }
+          is_grouped: false
+          group_info:
+            label: ''
+            description: ''
+            identifier: ''
+            optional: true
+            widget: select
+            multiple: false
+            remember: false
+            default_group: All
+            default_group_multiple: {  }
+            group_items: {  }
+          entity_type: eventseries
+          entity_field: created
+          plugin_id: date
+        created_1:
+          id: created_1
+          table: eventseries_field_data
+          field: created
+          relationship: none
+          group_type: group
+          admin_label: ''
+          operator: '<='
+          value:
+            min: ''
+            max: ''
+            value: ''
+            type: date
+          group: 1
+          exposed: true
+          expose:
+            operator_id: created_1_op
+            label: 'Created Before'
+            description: ''
+            use_operator: false
+            operator: created_1_op
+            identifier: created_1
+            required: false
+            remember: false
+            multiple: false
+            remember_roles:
+              authenticated: authenticated
+              anonymous: '0'
+              administrator: '0'
+            placeholder: ''
+            min_placeholder: ''
+            max_placeholder: ''
+            operator_limit_selection: false
+            operator_list: {  }
+          is_grouped: false
+          group_info:
+            label: ''
+            description: ''
+            identifier: ''
+            optional: true
+            widget: select
+            multiple: false
+            remember: false
+            default_group: All
+            default_group_multiple: {  }
+            group_items: {  }
+          entity_type: eventseries
+          entity_field: created
+          plugin_id: date
+        status:
+          id: status
+          table: eventseries_field_data
+          field: status
+          relationship: none
+          group_type: group
+          admin_label: ''
+          operator: '='
+          value: All
+          group: 1
+          exposed: true
+          expose:
+            operator_id: ''
+            label: Published
+            description: ''
+            use_operator: false
+            operator: status_op
+            identifier: status
+            required: false
+            remember: false
+            multiple: false
+            remember_roles:
+              authenticated: authenticated
+              anonymous: '0'
+              administrator: '0'
+            operator_limit_selection: false
+            operator_list: {  }
+          is_grouped: false
+          group_info:
+            label: ''
+            description: ''
+            identifier: ''
+            optional: true
+            widget: select
+            multiple: false
+            remember: false
+            default_group: All
+            default_group_multiple: {  }
+            group_items: {  }
+          entity_type: eventseries
+          entity_field: status
+          plugin_id: boolean
+      sorts:
+        title:
+          id: title
+          table: eventseries_field_data
+          field: title
+          relationship: none
+          group_type: group
+          admin_label: ''
+          order: ASC
+          exposed: false
+          expose:
+            label: ''
+          entity_type: eventseries
+          entity_field: title
+          plugin_id: standard
+      title: 'Event Series'
+      header: {  }
+      footer: {  }
+      empty: {  }
+      relationships:
+        uid:
+          id: uid
+          table: eventseries_field_data
+          field: uid
+          relationship: none
+          group_type: group
+          admin_label: User
+          required: false
+          entity_type: eventseries
+          entity_field: uid
+          plugin_id: standard
+      arguments: {  }
+      display_extenders: {  }
+      filter_groups:
+        operator: AND
+        groups:
+          1: AND
+    cache_metadata:
+      max-age: -1
+      contexts:
+        - 'languages:language_content'
+        - 'languages:language_interface'
+        - url
+        - url.query_args
+        - user.permissions
+      tags: {  }
+  admin_page:
+    display_plugin: page
+    id: admin_page
+    display_title: Page
+    position: 1
+    display_options:
+      display_extenders: {  }
+      path: admin/content/events/series
+      access:
+        type: perm
+        options:
+          perm: 'access eventseries overview'
+      defaults:
+        access: false
+        pager: false
+        filters: false
+        filter_groups: false
+      pager:
+        type: full
+        options:
+          items_per_page: 25
+          offset: 0
+          id: 0
+          total_pages: null
+          tags:
+            previous: ‹‹
+            next: ››
+            first: '« First'
+            last: 'Last »'
+          expose:
+            items_per_page: false
+            items_per_page_label: 'Items per page'
+            items_per_page_options: '5, 10, 25, 50'
+            items_per_page_options_all: false
+            items_per_page_options_all_label: '- All -'
+            offset: false
+            offset_label: Offset
+          quantity: 9
+      filters:
+        title:
+          id: title
+          table: eventseries_field_data
+          field: title
+          relationship: none
+          group_type: group
+          admin_label: ''
+          operator: contains
+          value: ''
+          group: 1
+          exposed: true
+          expose:
+            operator_id: title_op
+            label: Title
+            description: ''
+            use_operator: false
+            operator: title_op
+            identifier: title
+            required: false
+            remember: false
+            multiple: false
+            remember_roles:
+              authenticated: authenticated
+              anonymous: '0'
+              administrator: '0'
+            placeholder: ''
+            operator_limit_selection: false
+            operator_list: {  }
+          is_grouped: false
+          group_info:
+            label: ''
+            description: ''
+            identifier: ''
+            optional: true
+            widget: select
+            multiple: false
+            remember: false
+            default_group: All
+            default_group_multiple: {  }
+            group_items: {  }
+          entity_type: eventseries
+          entity_field: title
+          plugin_id: string
+        type:
+          id: type
+          table: eventseries_field_data
+          field: type
+          relationship: none
+          group_type: group
+          admin_label: ''
+          operator: in
+          value: {  }
+          group: 1
+          exposed: true
+          expose:
+            operator_id: type_op
+            label: Type
+            description: ''
+            use_operator: false
+            operator: type_op
+            identifier: type
+            required: false
+            remember: false
+            multiple: false
+            remember_roles:
+              authenticated: authenticated
+              anonymous: '0'
+              administrator: '0'
+            reduce: false
+            operator_limit_selection: false
+            operator_list: {  }
+          is_grouped: false
+          group_info:
+            label: ''
+            description: ''
+            identifier: ''
+            optional: true
+            widget: select
+            multiple: false
+            remember: false
+            default_group: All
+            default_group_multiple: {  }
+            group_items: {  }
+          entity_type: eventseries
+          entity_field: type
+          plugin_id: bundle
+        recur_type:
+          id: recur_type
+          table: eventseries_field_data
+          field: recur_type
+          relationship: none
+          group_type: group
+          admin_label: ''
+          operator: contains
+          value: ''
+          group: 1
+          exposed: true
+          expose:
+            operator_id: recur_type_op
+            label: 'Recur Type'
+            description: ''
+            use_operator: false
+            operator: recur_type_op
+            operator_limit_selection: false
+            operator_list: {  }
+            identifier: recur_type
+            required: false
+            remember: false
+            multiple: false
+            remember_roles:
+              authenticated: authenticated
+              anonymous: '0'
+              administrator: '0'
+            placeholder: ''
+          is_grouped: true
+          group_info:
+            label: 'Recur Type'
+            description: ''
+            identifier: recur_type
+            optional: true
+            widget: select
+            multiple: false
+            remember: false
+            default_group: All
+            default_group_multiple: {  }
+            group_items:
+              1:
+                title: Consecutive
+                operator: contains
+                value: consecutive_recurring_date
+              2:
+                title: Daily
+                operator: contains
+                value: daily_recurring_date
+              3:
+                title: Weekly
+                operator: contains
+                value: weekly_recurring_date
+              4:
+                title: Monthly
+                operator: contains
+                value: monthly_recurring_date
+              5:
+                title: Custom
+                operator: contains
+                value: custom
+          entity_type: eventseries
+          entity_field: recur_type
+          plugin_id: string
+        status:
+          id: status
+          table: eventseries_field_data
+          field: status
+          relationship: none
+          group_type: group
+          admin_label: ''
+          operator: '='
+          value: All
+          group: 1
+          exposed: true
+          expose:
+            operator_id: ''
+            label: Published
+            description: ''
+            use_operator: false
+            operator: status_op
+            operator_limit_selection: false
+            operator_list: {  }
+            identifier: status
+            required: false
+            remember: false
+            multiple: false
+            remember_roles:
+              authenticated: authenticated
+              anonymous: '0'
+              administrator: '0'
+          is_grouped: true
+          group_info:
+            label: Published
+            description: ''
+            identifier: status
+            optional: true
+            widget: select
+            multiple: false
+            remember: false
+            default_group: All
+            default_group_multiple: {  }
+            group_items:
+              1:
+                title: Published
+                operator: '='
+                value: '1'
+              2:
+                title: Unpublished
+                operator: '='
+                value: '0'
+          entity_type: eventseries
+          entity_field: status
+          plugin_id: boolean
+      filter_groups:
+        operator: AND
+        groups:
+          1: AND
+    cache_metadata:
+      max-age: -1
+      contexts:
+        - 'languages:language_content'
+        - 'languages:language_interface'
+        - url
+        - url.query_args
+        - user.permissions
+      tags: {  }
+  eventseries_listing:
+    display_plugin: page
+    id: eventseries_listing
+    display_title: Page
+    position: 1
+    display_options:
+      display_extenders: {  }
+      path: events/series
+      menu:
+        type: normal
+        title: 'Event Series'
+        description: 'Event series listing'
+        expanded: false
+        parent: ''
+        weight: 0
+        context: '0'
+        menu_name: main
+      style:
+        type: default
+        options:
+          grouping: {  }
+          row_class: ''
+          default_row_class: true
+      defaults:
+        style: false
+        row: false
+        filters: false
+        filter_groups: false
+      row:
+        type: 'entity:eventseries'
+        options:
+          relationship: none
+          view_mode: list
+      filters:
+        title:
+          id: title
+          table: eventseries_field_data
+          field: title
+          relationship: none
+          group_type: group
+          admin_label: ''
+          operator: contains
+          value: ''
+          group: 1
+          exposed: true
+          expose:
+            operator_id: title_op
+            label: Title
+            description: ''
+            use_operator: false
+            operator: title_op
+            identifier: title
+            required: false
+            remember: false
+            multiple: false
+            remember_roles:
+              authenticated: authenticated
+              anonymous: '0'
+              administrator: '0'
+            placeholder: ''
+            operator_limit_selection: false
+            operator_list: {  }
+          is_grouped: false
+          group_info:
+            label: ''
+            description: ''
+            identifier: ''
+            optional: true
+            widget: select
+            multiple: false
+            remember: false
+            default_group: All
+            default_group_multiple: {  }
+            group_items: {  }
+          entity_type: eventseries
+          entity_field: title
+          plugin_id: string
+        status:
+          id: status
+          table: eventseries_field_data
+          field: status
+          relationship: none
+          group_type: group
+          admin_label: ''
+          operator: '='
+          value: '1'
+          group: 1
+          exposed: false
+          expose:
+            operator_id: ''
+            label: ''
+            description: ''
+            use_operator: false
+            operator: ''
+            operator_limit_selection: false
+            operator_list: {  }
+            identifier: ''
+            required: false
+            remember: false
+            multiple: false
+            remember_roles:
+              authenticated: authenticated
+          is_grouped: false
+          group_info:
+            label: ''
+            description: ''
+            identifier: ''
+            optional: true
+            widget: select
+            multiple: false
+            remember: false
+            default_group: All
+            default_group_multiple: {  }
+            group_items: {  }
+          entity_type: eventseries
+          entity_field: status
+          plugin_id: boolean
+      filter_groups:
+        operator: AND
+        groups:
+          1: AND
+    cache_metadata:
+      max-age: -1
+      contexts:
+        - 'languages:language_content'
+        - 'languages:language_interface'
+        - url
+        - url.query_args
+        - user.permissions
+      tags: {  }
diff --git a/modules/recurring_events_views/config/install/views.view.events.yml b/modules/recurring_events_views/config/install/views.view.events.yml
new file mode 100644
index 0000000000000000000000000000000000000000..f9d6805cdb4eae2a31d4b3a3d2e6765f03d33ed2
--- /dev/null
+++ b/modules/recurring_events_views/config/install/views.view.events.yml
@@ -0,0 +1,2127 @@
+langcode: en
+status: true
+dependencies:
+  config:
+    - core.entity_view_mode.eventinstance.list
+    - system.menu.main
+  module:
+    - datetime
+    - datetime_range
+    - recurring_events
+    - user
+id: events
+label: Events
+module: views
+description: 'A view showing all the event instances on the site'
+tag: ''
+base_table: eventinstance_field_data
+base_field: id
+display:
+  default:
+    display_plugin: default
+    id: default
+    display_title: Master
+    position: 0
+    display_options:
+      access:
+        type: perm
+        options:
+          perm: 'view eventinstance entity'
+      cache:
+        type: tag
+        options: {  }
+      query:
+        type: views_query
+        options:
+          disable_sql_rewrite: false
+          distinct: false
+          replica: false
+          query_comment: ''
+          query_tags: {  }
+      exposed_form:
+        type: basic
+        options:
+          submit_button: Apply
+          reset_button: false
+          reset_button_label: Reset
+          exposed_sorts_label: 'Sort by'
+          expose_sort_order: true
+          sort_asc_label: Asc
+          sort_desc_label: Desc
+      pager:
+        type: full
+        options:
+          items_per_page: 10
+          offset: 0
+          id: 0
+          total_pages: null
+          tags:
+            previous: ‹‹
+            next: ››
+            first: '« First'
+            last: 'Last »'
+          expose:
+            items_per_page: false
+            items_per_page_label: 'Items per page'
+            items_per_page_options: '5, 10, 25, 50'
+            items_per_page_options_all: false
+            items_per_page_options_all_label: '- All -'
+            offset: false
+            offset_label: Offset
+          quantity: 9
+      style:
+        type: table
+        options:
+          grouping: {  }
+          row_class: ''
+          default_row_class: true
+          override: true
+          sticky: false
+          caption: ''
+          summary: ''
+          description: ''
+          columns:
+            title: title
+            view_eventseries: view_eventseries
+            view_eventinstance: view_eventinstance
+            title_2: title_2
+            title_1: title_1
+            date__value: date__value
+          info:
+            title:
+              sortable: false
+              default_sort_order: asc
+              align: ''
+              separator: ''
+              empty_column: false
+              responsive: ''
+            view_eventseries:
+              sortable: false
+              default_sort_order: asc
+              align: ''
+              separator: ''
+              empty_column: false
+              responsive: ''
+            view_eventinstance:
+              sortable: false
+              default_sort_order: asc
+              align: ''
+              separator: ''
+              empty_column: false
+              responsive: ''
+            title_2:
+              sortable: false
+              default_sort_order: asc
+              align: ''
+              separator: ''
+              empty_column: false
+              responsive: ''
+            title_1:
+              sortable: false
+              default_sort_order: asc
+              align: ''
+              separator: ''
+              empty_column: false
+              responsive: ''
+            date__value:
+              sortable: false
+              default_sort_order: asc
+              align: ''
+              separator: ''
+              empty_column: false
+              responsive: ''
+          default: '-1'
+          empty_table: false
+      row:
+        type: 'entity:eventinstance'
+      fields:
+        title:
+          id: title
+          table: eventseries_field_data
+          field: title
+          relationship: eventseries_id
+          group_type: group
+          admin_label: ''
+          label: ''
+          exclude: true
+          alter:
+            alter_text: false
+            text: ''
+            make_link: false
+            path: ''
+            absolute: false
+            external: false
+            replace_spaces: false
+            path_case: none
+            trim_whitespace: false
+            alt: ''
+            rel: ''
+            link_class: ''
+            prefix: ''
+            suffix: ''
+            target: ''
+            nl2br: false
+            max_length: 0
+            word_boundary: true
+            ellipsis: true
+            more_link: false
+            more_link_text: ''
+            more_link_path: ''
+            strip_tags: false
+            trim: false
+            preserve_tags: ''
+            html: false
+          element_type: ''
+          element_class: ''
+          element_label_type: ''
+          element_label_class: ''
+          element_label_colon: false
+          element_wrapper_type: ''
+          element_wrapper_class: ''
+          element_default_classes: true
+          empty: ''
+          hide_empty: false
+          empty_zero: false
+          hide_alter_empty: true
+          click_sort_column: value
+          type: string
+          settings:
+            link_to_entity: false
+          group_column: value
+          group_columns: {  }
+          group_rows: true
+          delta_limit: 0
+          delta_offset: 0
+          delta_reversed: false
+          delta_first_last: false
+          multi_type: separator
+          separator: ', '
+          field_api_classes: false
+          entity_type: eventseries
+          entity_field: title
+          plugin_id: field
+        view_eventseries:
+          id: view_eventseries
+          table: eventseries
+          field: view_eventseries
+          relationship: eventseries_id
+          group_type: group
+          admin_label: ''
+          label: ''
+          exclude: true
+          alter:
+            alter_text: false
+            text: ''
+            make_link: false
+            path: ''
+            absolute: false
+            external: false
+            replace_spaces: false
+            path_case: none
+            trim_whitespace: false
+            alt: ''
+            rel: ''
+            link_class: ''
+            prefix: ''
+            suffix: ''
+            target: ''
+            nl2br: false
+            max_length: 0
+            word_boundary: true
+            ellipsis: true
+            more_link: false
+            more_link_text: ''
+            more_link_path: ''
+            strip_tags: false
+            trim: false
+            preserve_tags: ''
+            html: false
+          element_type: ''
+          element_class: ''
+          element_label_type: ''
+          element_label_class: ''
+          element_label_colon: false
+          element_wrapper_type: ''
+          element_wrapper_class: ''
+          element_default_classes: true
+          empty: ''
+          hide_empty: false
+          empty_zero: false
+          hide_alter_empty: true
+          text: view
+          output_url_as_text: true
+          absolute: false
+          entity_type: eventseries
+          plugin_id: entity_link
+        view_eventinstance:
+          id: view_eventinstance
+          table: eventinstance
+          field: view_eventinstance
+          relationship: none
+          group_type: group
+          admin_label: ''
+          label: ''
+          exclude: true
+          alter:
+            alter_text: false
+            text: '{{ title }}'
+            make_link: false
+            path: ''
+            absolute: false
+            external: false
+            replace_spaces: false
+            path_case: none
+            trim_whitespace: false
+            alt: ''
+            rel: ''
+            link_class: ''
+            prefix: ''
+            suffix: ''
+            target: ''
+            nl2br: false
+            max_length: 0
+            word_boundary: true
+            ellipsis: true
+            more_link: false
+            more_link_text: ''
+            more_link_path: ''
+            strip_tags: false
+            trim: false
+            preserve_tags: ''
+            html: false
+          element_type: ''
+          element_class: ''
+          element_label_type: ''
+          element_label_class: ''
+          element_label_colon: false
+          element_wrapper_type: ''
+          element_wrapper_class: ''
+          element_default_classes: true
+          empty: ''
+          hide_empty: false
+          empty_zero: false
+          hide_alter_empty: true
+          text: ''
+          output_url_as_text: true
+          absolute: false
+          entity_type: eventinstance
+          plugin_id: entity_link
+        title_2:
+          id: title_2
+          table: eventseries_field_data
+          field: title
+          relationship: eventseries_id
+          group_type: group
+          admin_label: ''
+          label: 'Event Name'
+          exclude: false
+          alter:
+            alter_text: true
+            text: '{{ title }}'
+            make_link: true
+            path: '{{ view_eventinstance }}'
+            absolute: false
+            external: false
+            replace_spaces: false
+            path_case: none
+            trim_whitespace: false
+            alt: ''
+            rel: ''
+            link_class: ''
+            prefix: ''
+            suffix: ''
+            target: ''
+            nl2br: false
+            max_length: 0
+            word_boundary: true
+            ellipsis: true
+            more_link: false
+            more_link_text: ''
+            more_link_path: ''
+            strip_tags: false
+            trim: false
+            preserve_tags: ''
+            html: false
+          element_type: ''
+          element_class: ''
+          element_label_type: ''
+          element_label_class: ''
+          element_label_colon: true
+          element_wrapper_type: ''
+          element_wrapper_class: ''
+          element_default_classes: true
+          empty: ''
+          hide_empty: false
+          empty_zero: false
+          hide_alter_empty: true
+          click_sort_column: value
+          type: string
+          settings:
+            link_to_entity: false
+          group_column: value
+          group_columns: {  }
+          group_rows: true
+          delta_limit: 0
+          delta_offset: 0
+          delta_reversed: false
+          delta_first_last: false
+          multi_type: separator
+          separator: ', '
+          field_api_classes: false
+          entity_type: eventseries
+          entity_field: title
+          plugin_id: field
+        title_1:
+          id: title_1
+          table: eventseries_field_data
+          field: title
+          relationship: eventseries_id
+          group_type: group
+          admin_label: ''
+          label: Series
+          exclude: false
+          alter:
+            alter_text: true
+            text: '{{ "View Series"|t }}'
+            make_link: true
+            path: '{{ view_eventseries }}'
+            absolute: false
+            external: false
+            replace_spaces: false
+            path_case: none
+            trim_whitespace: false
+            alt: ''
+            rel: ''
+            link_class: ''
+            prefix: ''
+            suffix: ''
+            target: ''
+            nl2br: false
+            max_length: 0
+            word_boundary: true
+            ellipsis: true
+            more_link: false
+            more_link_text: ''
+            more_link_path: ''
+            strip_tags: false
+            trim: false
+            preserve_tags: ''
+            html: false
+          element_type: ''
+          element_class: ''
+          element_label_type: ''
+          element_label_class: ''
+          element_label_colon: true
+          element_wrapper_type: ''
+          element_wrapper_class: ''
+          element_default_classes: true
+          empty: ''
+          hide_empty: false
+          empty_zero: false
+          hide_alter_empty: true
+          click_sort_column: value
+          type: string
+          settings:
+            link_to_entity: true
+          group_column: value
+          group_columns: {  }
+          group_rows: true
+          delta_limit: 0
+          delta_offset: 0
+          delta_reversed: false
+          delta_first_last: false
+          multi_type: separator
+          separator: ', '
+          field_api_classes: false
+          entity_type: eventseries
+          entity_field: title
+          plugin_id: field
+        type:
+          id: type
+          table: eventinstance_field_data
+          field: type
+          relationship: none
+          group_type: group
+          admin_label: ''
+          label: Type
+          exclude: false
+          alter:
+            alter_text: false
+            text: ''
+            make_link: false
+            path: ''
+            absolute: false
+            external: false
+            replace_spaces: false
+            path_case: none
+            trim_whitespace: false
+            alt: ''
+            rel: ''
+            link_class: ''
+            prefix: ''
+            suffix: ''
+            target: ''
+            nl2br: false
+            max_length: 0
+            word_boundary: true
+            ellipsis: true
+            more_link: false
+            more_link_text: ''
+            more_link_path: ''
+            strip_tags: false
+            trim: false
+            preserve_tags: ''
+            html: false
+          element_type: ''
+          element_class: ''
+          element_label_type: ''
+          element_label_class: ''
+          element_label_colon: true
+          element_wrapper_type: ''
+          element_wrapper_class: ''
+          element_default_classes: true
+          empty: ''
+          hide_empty: false
+          empty_zero: false
+          hide_alter_empty: true
+          click_sort_column: target_id
+          type: entity_reference_label
+          settings:
+            link: false
+          group_column: target_id
+          group_columns: {  }
+          group_rows: true
+          delta_limit: 0
+          delta_offset: 0
+          delta_reversed: false
+          delta_first_last: false
+          multi_type: separator
+          separator: ', '
+          field_api_classes: false
+          entity_type: eventinstance
+          entity_field: type
+          plugin_id: field
+        date__value:
+          id: date__value
+          table: eventinstance_field_data
+          field: date__value
+          relationship: none
+          group_type: group
+          admin_label: ''
+          label: 'Event Date'
+          exclude: false
+          alter:
+            alter_text: false
+            text: ''
+            make_link: false
+            path: ''
+            absolute: false
+            external: false
+            replace_spaces: false
+            path_case: none
+            trim_whitespace: false
+            alt: ''
+            rel: ''
+            link_class: ''
+            prefix: ''
+            suffix: ''
+            target: ''
+            nl2br: false
+            max_length: 0
+            word_boundary: true
+            ellipsis: true
+            more_link: false
+            more_link_text: ''
+            more_link_path: ''
+            strip_tags: false
+            trim: false
+            preserve_tags: ''
+            html: false
+          element_type: ''
+          element_class: ''
+          element_label_type: ''
+          element_label_class: ''
+          element_label_colon: true
+          element_wrapper_type: ''
+          element_wrapper_class: ''
+          element_default_classes: true
+          empty: ''
+          hide_empty: false
+          empty_zero: false
+          hide_alter_empty: true
+          click_sort_column: value
+          type: daterange_default
+          settings:
+            timezone_override: ''
+            format_type: medium
+            fromto: start_date
+            separator: '-'
+          group_column: value
+          group_columns: {  }
+          group_rows: true
+          delta_limit: 0
+          delta_offset: 0
+          delta_reversed: false
+          delta_first_last: false
+          multi_type: separator
+          separator: ', '
+          field_api_classes: false
+          entity_type: eventinstance
+          entity_field: date
+          plugin_id: field
+        uid:
+          id: uid
+          table: eventinstance_field_data
+          field: uid
+          relationship: none
+          group_type: group
+          admin_label: ''
+          label: Author
+          exclude: false
+          alter:
+            alter_text: false
+            text: ''
+            make_link: false
+            path: ''
+            absolute: false
+            external: false
+            replace_spaces: false
+            path_case: none
+            trim_whitespace: false
+            alt: ''
+            rel: ''
+            link_class: ''
+            prefix: ''
+            suffix: ''
+            target: ''
+            nl2br: false
+            max_length: 0
+            word_boundary: true
+            ellipsis: true
+            more_link: false
+            more_link_text: ''
+            more_link_path: ''
+            strip_tags: false
+            trim: false
+            preserve_tags: ''
+            html: false
+          element_type: ''
+          element_class: ''
+          element_label_type: ''
+          element_label_class: ''
+          element_label_colon: true
+          element_wrapper_type: ''
+          element_wrapper_class: ''
+          element_default_classes: true
+          empty: ''
+          hide_empty: false
+          empty_zero: false
+          hide_alter_empty: true
+          click_sort_column: target_id
+          type: entity_reference_label
+          settings:
+            link: true
+          group_column: target_id
+          group_columns: {  }
+          group_rows: true
+          delta_limit: 0
+          delta_offset: 0
+          delta_reversed: false
+          delta_first_last: false
+          multi_type: separator
+          separator: ', '
+          field_api_classes: false
+          entity_type: eventinstance
+          entity_field: uid
+          plugin_id: field
+        status:
+          id: status
+          table: eventinstance_field_data
+          field: status
+          relationship: none
+          group_type: group
+          admin_label: ''
+          label: Published
+          exclude: false
+          alter:
+            alter_text: false
+            text: ''
+            make_link: false
+            path: ''
+            absolute: false
+            external: false
+            replace_spaces: false
+            path_case: none
+            trim_whitespace: false
+            alt: ''
+            rel: ''
+            link_class: ''
+            prefix: ''
+            suffix: ''
+            target: ''
+            nl2br: false
+            max_length: 0
+            word_boundary: true
+            ellipsis: true
+            more_link: false
+            more_link_text: ''
+            more_link_path: ''
+            strip_tags: false
+            trim: false
+            preserve_tags: ''
+            html: false
+          element_type: ''
+          element_class: ''
+          element_label_type: ''
+          element_label_class: ''
+          element_label_colon: true
+          element_wrapper_type: ''
+          element_wrapper_class: ''
+          element_default_classes: true
+          empty: ''
+          hide_empty: false
+          empty_zero: false
+          hide_alter_empty: true
+          click_sort_column: value
+          type: boolean
+          settings:
+            format: yes-no
+            format_custom_true: ''
+            format_custom_false: ''
+          group_column: value
+          group_columns: {  }
+          group_rows: true
+          delta_limit: 0
+          delta_offset: 0
+          delta_reversed: false
+          delta_first_last: false
+          multi_type: separator
+          separator: ', '
+          field_api_classes: false
+          entity_type: eventinstance
+          entity_field: status
+          plugin_id: field
+        created:
+          id: created
+          table: eventinstance_field_data
+          field: created
+          relationship: none
+          group_type: group
+          admin_label: ''
+          label: Created
+          exclude: false
+          alter:
+            alter_text: false
+            text: ''
+            make_link: false
+            path: ''
+            absolute: false
+            external: false
+            replace_spaces: false
+            path_case: none
+            trim_whitespace: false
+            alt: ''
+            rel: ''
+            link_class: ''
+            prefix: ''
+            suffix: ''
+            target: ''
+            nl2br: false
+            max_length: 0
+            word_boundary: true
+            ellipsis: true
+            more_link: false
+            more_link_text: ''
+            more_link_path: ''
+            strip_tags: false
+            trim: false
+            preserve_tags: ''
+            html: false
+          element_type: ''
+          element_class: ''
+          element_label_type: ''
+          element_label_class: ''
+          element_label_colon: true
+          element_wrapper_type: ''
+          element_wrapper_class: ''
+          element_default_classes: true
+          empty: ''
+          hide_empty: false
+          empty_zero: false
+          hide_alter_empty: true
+          click_sort_column: value
+          type: timestamp
+          settings:
+            date_format: medium
+            custom_date_format: ''
+            timezone: ''
+          group_column: value
+          group_columns: {  }
+          group_rows: true
+          delta_limit: 0
+          delta_offset: 0
+          delta_reversed: false
+          delta_first_last: false
+          multi_type: separator
+          separator: ', '
+          field_api_classes: false
+          entity_type: eventinstance
+          entity_field: created
+          plugin_id: field
+        changed:
+          id: changed
+          table: eventinstance_field_data
+          field: changed
+          relationship: none
+          group_type: group
+          admin_label: ''
+          label: Changed
+          exclude: false
+          alter:
+            alter_text: false
+            text: ''
+            make_link: false
+            path: ''
+            absolute: false
+            external: false
+            replace_spaces: false
+            path_case: none
+            trim_whitespace: false
+            alt: ''
+            rel: ''
+            link_class: ''
+            prefix: ''
+            suffix: ''
+            target: ''
+            nl2br: false
+            max_length: 0
+            word_boundary: true
+            ellipsis: true
+            more_link: false
+            more_link_text: ''
+            more_link_path: ''
+            strip_tags: false
+            trim: false
+            preserve_tags: ''
+            html: false
+          element_type: ''
+          element_class: ''
+          element_label_type: ''
+          element_label_class: ''
+          element_label_colon: true
+          element_wrapper_type: ''
+          element_wrapper_class: ''
+          element_default_classes: true
+          empty: ''
+          hide_empty: false
+          empty_zero: false
+          hide_alter_empty: true
+          click_sort_column: value
+          type: timestamp
+          settings:
+            date_format: medium
+            custom_date_format: ''
+            timezone: ''
+          group_column: value
+          group_columns: {  }
+          group_rows: true
+          delta_limit: 0
+          delta_offset: 0
+          delta_reversed: false
+          delta_first_last: false
+          multi_type: separator
+          separator: ', '
+          field_api_classes: false
+          entity_type: eventinstance
+          entity_field: changed
+          plugin_id: field
+        operations:
+          id: operations
+          table: eventinstance
+          field: operations
+          relationship: none
+          group_type: group
+          admin_label: ''
+          label: Operations
+          exclude: false
+          alter:
+            alter_text: false
+            text: ''
+            make_link: false
+            path: ''
+            absolute: false
+            external: false
+            replace_spaces: false
+            path_case: none
+            trim_whitespace: false
+            alt: ''
+            rel: ''
+            link_class: ''
+            prefix: ''
+            suffix: ''
+            target: ''
+            nl2br: false
+            max_length: 0
+            word_boundary: true
+            ellipsis: true
+            more_link: false
+            more_link_text: ''
+            more_link_path: ''
+            strip_tags: false
+            trim: false
+            preserve_tags: ''
+            html: false
+          element_type: ''
+          element_class: ''
+          element_label_type: ''
+          element_label_class: ''
+          element_label_colon: true
+          element_wrapper_type: ''
+          element_wrapper_class: ''
+          element_default_classes: true
+          empty: ''
+          hide_empty: false
+          empty_zero: false
+          hide_alter_empty: true
+          destination: false
+          entity_type: eventinstance
+          plugin_id: entity_operations
+      filters:
+        title:
+          id: title
+          table: eventseries_field_data
+          field: title
+          relationship: eventseries_id
+          group_type: group
+          admin_label: ''
+          operator: contains
+          value: ''
+          group: 1
+          exposed: true
+          expose:
+            operator_id: title_op
+            label: 'Event Name'
+            description: ''
+            use_operator: false
+            operator: title_op
+            identifier: title
+            required: false
+            remember: false
+            multiple: false
+            remember_roles:
+              authenticated: authenticated
+              anonymous: '0'
+              administrator: '0'
+            placeholder: ''
+            operator_limit_selection: false
+            operator_list: {  }
+          is_grouped: false
+          group_info:
+            label: ''
+            description: ''
+            identifier: ''
+            optional: true
+            widget: select
+            multiple: false
+            remember: false
+            default_group: All
+            default_group_multiple: {  }
+            group_items: {  }
+          entity_type: eventseries
+          entity_field: title
+          plugin_id: string
+        type:
+          id: type
+          table: eventinstance_field_data
+          field: type
+          relationship: none
+          group_type: group
+          admin_label: ''
+          operator: in
+          value: {  }
+          group: 1
+          exposed: true
+          expose:
+            operator_id: type_op
+            label: Type
+            description: ''
+            use_operator: false
+            operator: type_op
+            identifier: type
+            required: false
+            remember: false
+            multiple: false
+            remember_roles:
+              authenticated: authenticated
+              anonymous: '0'
+              administrator: '0'
+            reduce: false
+            operator_limit_selection: false
+            operator_list: {  }
+          is_grouped: false
+          group_info:
+            label: ''
+            description: ''
+            identifier: ''
+            optional: true
+            widget: select
+            multiple: false
+            remember: false
+            default_group: All
+            default_group_multiple: {  }
+            group_items: {  }
+          entity_type: eventinstance
+          entity_field: type
+          plugin_id: bundle
+        uid:
+          id: uid
+          table: users_field_data
+          field: uid
+          relationship: uid
+          group_type: group
+          admin_label: ''
+          operator: in
+          value: {  }
+          group: 1
+          exposed: true
+          expose:
+            operator_id: uid_op
+            label: Author
+            description: ''
+            use_operator: false
+            operator: uid_op
+            identifier: uid
+            required: false
+            remember: false
+            multiple: false
+            remember_roles:
+              authenticated: authenticated
+              anonymous: '0'
+              administrator: '0'
+            reduce: false
+            operator_limit_selection: false
+            operator_list: {  }
+          is_grouped: false
+          group_info:
+            label: ''
+            description: ''
+            identifier: ''
+            optional: true
+            widget: select
+            multiple: false
+            remember: false
+            default_group: All
+            default_group_multiple: {  }
+            group_items: {  }
+          entity_type: user
+          entity_field: uid
+          plugin_id: user_name
+        created:
+          id: created
+          table: eventinstance_field_data
+          field: created
+          relationship: none
+          group_type: group
+          admin_label: ''
+          operator: '>='
+          value:
+            min: ''
+            max: ''
+            value: ''
+            type: date
+          group: 1
+          exposed: true
+          expose:
+            operator_id: created_op
+            label: 'Created After'
+            description: ''
+            use_operator: false
+            operator: created_op
+            identifier: created
+            required: false
+            remember: false
+            multiple: false
+            remember_roles:
+              authenticated: authenticated
+              anonymous: '0'
+              administrator: '0'
+            placeholder: ''
+            min_placeholder: ''
+            max_placeholder: ''
+            operator_limit_selection: false
+            operator_list: {  }
+          is_grouped: false
+          group_info:
+            label: ''
+            description: ''
+            identifier: ''
+            optional: true
+            widget: select
+            multiple: false
+            remember: false
+            default_group: All
+            default_group_multiple: {  }
+            group_items: {  }
+          entity_type: eventinstance
+          entity_field: created
+          plugin_id: date
+        created_1:
+          id: created_1
+          table: eventinstance_field_data
+          field: created
+          relationship: none
+          group_type: group
+          admin_label: ''
+          operator: '<='
+          value:
+            min: ''
+            max: ''
+            value: ''
+            type: date
+          group: 1
+          exposed: true
+          expose:
+            operator_id: created_1_op
+            label: 'Created Before'
+            description: ''
+            use_operator: false
+            operator: created_1_op
+            identifier: created_1
+            required: false
+            remember: false
+            multiple: false
+            remember_roles:
+              authenticated: authenticated
+              anonymous: '0'
+              administrator: '0'
+            placeholder: ''
+            min_placeholder: ''
+            max_placeholder: ''
+            operator_limit_selection: false
+            operator_list: {  }
+          is_grouped: false
+          group_info:
+            label: ''
+            description: ''
+            identifier: ''
+            optional: true
+            widget: select
+            multiple: false
+            remember: false
+            default_group: All
+            default_group_multiple: {  }
+            group_items: {  }
+          entity_type: eventinstance
+          entity_field: created
+          plugin_id: date
+        status:
+          id: status
+          table: eventinstance_field_data
+          field: status
+          relationship: none
+          group_type: group
+          admin_label: ''
+          operator: '='
+          value: All
+          group: 1
+          exposed: true
+          expose:
+            operator_id: ''
+            label: Published
+            description: ''
+            use_operator: false
+            operator: status_op
+            identifier: status
+            required: false
+            remember: false
+            multiple: false
+            remember_roles:
+              authenticated: authenticated
+              anonymous: '0'
+              administrator: '0'
+            operator_limit_selection: false
+            operator_list: {  }
+          is_grouped: false
+          group_info:
+            label: ''
+            description: ''
+            identifier: ''
+            optional: true
+            widget: select
+            multiple: false
+            remember: false
+            default_group: All
+            default_group_multiple: {  }
+            group_items: {  }
+          entity_type: eventinstance
+          entity_field: status
+          plugin_id: boolean
+      sorts:
+        date__value:
+          id: date__value
+          table: eventinstance_field_data
+          field: date__value
+          relationship: none
+          group_type: group
+          admin_label: ''
+          order: ASC
+          exposed: false
+          expose:
+            label: ''
+          entity_type: eventinstance
+          entity_field: date
+          plugin_id: standard
+        title:
+          id: title
+          table: eventseries_field_data
+          field: title
+          relationship: eventseries_id
+          group_type: group
+          admin_label: ''
+          order: ASC
+          exposed: false
+          expose:
+            label: ''
+          entity_type: eventseries
+          entity_field: title
+          plugin_id: standard
+      title: Events
+      header: {  }
+      footer: {  }
+      empty: {  }
+      relationships:
+        eventseries_id:
+          id: eventseries_id
+          table: eventinstance_field_data
+          field: eventseries_id
+          relationship: none
+          group_type: group
+          admin_label: 'Event series entity'
+          required: true
+          entity_type: eventinstance
+          entity_field: eventseries_id
+          plugin_id: standard
+        uid:
+          id: uid
+          table: eventinstance_field_data
+          field: uid
+          relationship: none
+          group_type: group
+          admin_label: User
+          required: false
+          entity_type: eventinstance
+          entity_field: uid
+          plugin_id: standard
+      arguments: {  }
+      display_extenders: {  }
+      filter_groups:
+        operator: AND
+        groups:
+          1: AND
+    cache_metadata:
+      max-age: -1
+      contexts:
+        - 'languages:language_content'
+        - 'languages:language_interface'
+        - url
+        - url.query_args
+        - user.permissions
+      tags: {  }
+  admin_page:
+    display_plugin: page
+    id: admin_page
+    display_title: Page
+    position: 1
+    display_options:
+      display_extenders: {  }
+      path: admin/content/events/instances
+      access:
+        type: perm
+        options:
+          perm: 'access eventinstance overview'
+      defaults:
+        access: false
+        pager: false
+        filters: false
+        filter_groups: false
+      pager:
+        type: full
+        options:
+          items_per_page: 25
+          offset: 0
+          id: 0
+          total_pages: null
+          tags:
+            previous: ‹‹
+            next: ››
+            first: '« First'
+            last: 'Last »'
+          expose:
+            items_per_page: false
+            items_per_page_label: 'Items per page'
+            items_per_page_options: '5, 10, 25, 50'
+            items_per_page_options_all: false
+            items_per_page_options_all_label: '- All -'
+            offset: false
+            offset_label: Offset
+          quantity: 9
+      exposed_block: false
+      filters:
+        title:
+          id: title
+          table: eventseries_field_data
+          field: title
+          relationship: eventseries_id
+          group_type: group
+          admin_label: ''
+          operator: contains
+          value: ''
+          group: 1
+          exposed: true
+          expose:
+            operator_id: title_op
+            label: 'Event Name'
+            description: ''
+            use_operator: false
+            operator: title_op
+            identifier: title
+            required: false
+            remember: false
+            multiple: false
+            remember_roles:
+              authenticated: authenticated
+              anonymous: '0'
+              administrator: '0'
+            placeholder: ''
+            operator_limit_selection: false
+            operator_list: {  }
+          is_grouped: false
+          group_info:
+            label: ''
+            description: ''
+            identifier: ''
+            optional: true
+            widget: select
+            multiple: false
+            remember: false
+            default_group: All
+            default_group_multiple: {  }
+            group_items: {  }
+          entity_type: eventseries
+          entity_field: title
+          plugin_id: string
+        type:
+          id: type
+          table: eventinstance_field_data
+          field: type
+          relationship: none
+          group_type: group
+          admin_label: ''
+          operator: in
+          value: {  }
+          group: 1
+          exposed: true
+          expose:
+            operator_id: type_op
+            label: Type
+            description: ''
+            use_operator: false
+            operator: type_op
+            identifier: type
+            required: false
+            remember: false
+            multiple: false
+            remember_roles:
+              authenticated: authenticated
+              anonymous: '0'
+              administrator: '0'
+            reduce: false
+            operator_limit_selection: false
+            operator_list: {  }
+          is_grouped: false
+          group_info:
+            label: ''
+            description: ''
+            identifier: ''
+            optional: true
+            widget: select
+            multiple: false
+            remember: false
+            default_group: All
+            default_group_multiple: {  }
+            group_items: {  }
+          entity_type: eventinstance
+          entity_field: type
+          plugin_id: bundle
+        date__value_2:
+          id: date__value_2
+          table: eventinstance_field_data
+          field: date__value
+          relationship: none
+          group_type: group
+          admin_label: ''
+          operator: '='
+          value:
+            min: ''
+            max: ''
+            value: ''
+            type: date
+          group: 1
+          exposed: true
+          expose:
+            operator_id: date__value_2_op
+            label: 'Event Date'
+            description: null
+            use_operator: false
+            operator: date__value_2_op
+            operator_limit_selection: false
+            operator_list: {  }
+            identifier: date__value_2
+            required: false
+            remember: false
+            multiple: false
+            remember_roles:
+              authenticated: authenticated
+            placeholder: null
+            min_placeholder: null
+            max_placeholder: null
+          is_grouped: true
+          group_info:
+            label: 'Event Date'
+            description: ''
+            identifier: date__value_2
+            optional: true
+            widget: select
+            multiple: false
+            remember: false
+            default_group: '1'
+            default_group_multiple: {  }
+            group_items:
+              1:
+                title: Future
+                operator: '>='
+                value:
+                  type: offset
+                  value: today
+                  min: ''
+                  max: ''
+              2:
+                title: Past
+                operator: '<='
+                value:
+                  type: offset
+                  value: today
+                  min: ''
+                  max: ''
+          entity_type: eventinstance
+          entity_field: date
+          plugin_id: datetime
+        status:
+          id: status
+          table: eventinstance_field_data
+          field: status
+          relationship: none
+          group_type: group
+          admin_label: ''
+          operator: '='
+          value: All
+          group: 1
+          exposed: true
+          expose:
+            operator_id: ''
+            label: Published
+            description: ''
+            use_operator: false
+            operator: status_op
+            operator_limit_selection: false
+            operator_list: {  }
+            identifier: status
+            required: false
+            remember: false
+            multiple: false
+            remember_roles:
+              authenticated: authenticated
+              anonymous: '0'
+              administrator: '0'
+          is_grouped: true
+          group_info:
+            label: Published
+            description: ''
+            identifier: status
+            optional: true
+            widget: select
+            multiple: false
+            remember: false
+            default_group: All
+            default_group_multiple: {  }
+            group_items:
+              1:
+                title: Published
+                operator: '='
+                value: '1'
+              2:
+                title: Unpublished
+                operator: '='
+                value: '0'
+          entity_type: eventinstance
+          entity_field: status
+          plugin_id: boolean
+      filter_groups:
+        operator: AND
+        groups:
+          1: AND
+    cache_metadata:
+      max-age: -1
+      contexts:
+        - 'languages:language_content'
+        - 'languages:language_interface'
+        - url
+        - url.query_args
+        - user.permissions
+      tags: {  }
+  events_listing:
+    display_plugin: page
+    id: events_listing
+    display_title: Page
+    position: 1
+    display_options:
+      display_extenders: {  }
+      path: events
+      menu:
+        type: normal
+        title: Events
+        description: 'Events listing page'
+        expanded: false
+        parent: ''
+        weight: 0
+        context: '0'
+        menu_name: main
+      fields:
+        title:
+          id: title
+          table: eventseries_field_data
+          field: title
+          relationship: eventseries_id
+          group_type: group
+          admin_label: ''
+          label: ''
+          exclude: true
+          alter:
+            alter_text: false
+            text: ''
+            make_link: false
+            path: ''
+            absolute: false
+            external: false
+            replace_spaces: false
+            path_case: none
+            trim_whitespace: false
+            alt: ''
+            rel: ''
+            link_class: ''
+            prefix: ''
+            suffix: ''
+            target: ''
+            nl2br: false
+            max_length: 0
+            word_boundary: true
+            ellipsis: true
+            more_link: false
+            more_link_text: ''
+            more_link_path: ''
+            strip_tags: false
+            trim: false
+            preserve_tags: ''
+            html: false
+          element_type: ''
+          element_class: ''
+          element_label_type: ''
+          element_label_class: ''
+          element_label_colon: false
+          element_wrapper_type: ''
+          element_wrapper_class: ''
+          element_default_classes: true
+          empty: ''
+          hide_empty: false
+          empty_zero: false
+          hide_alter_empty: true
+          click_sort_column: value
+          type: string
+          settings:
+            link_to_entity: false
+          group_column: value
+          group_columns: {  }
+          group_rows: true
+          delta_limit: 0
+          delta_offset: 0
+          delta_reversed: false
+          delta_first_last: false
+          multi_type: separator
+          separator: ', '
+          field_api_classes: false
+          entity_type: eventseries
+          entity_field: title
+          plugin_id: field
+        view_eventseries:
+          id: view_eventseries
+          table: eventseries
+          field: view_eventseries
+          relationship: eventseries_id
+          group_type: group
+          admin_label: ''
+          label: ''
+          exclude: true
+          alter:
+            alter_text: false
+            text: ''
+            make_link: false
+            path: ''
+            absolute: false
+            external: false
+            replace_spaces: false
+            path_case: none
+            trim_whitespace: false
+            alt: ''
+            rel: ''
+            link_class: ''
+            prefix: ''
+            suffix: ''
+            target: ''
+            nl2br: false
+            max_length: 0
+            word_boundary: true
+            ellipsis: true
+            more_link: false
+            more_link_text: ''
+            more_link_path: ''
+            strip_tags: false
+            trim: false
+            preserve_tags: ''
+            html: false
+          element_type: ''
+          element_class: ''
+          element_label_type: ''
+          element_label_class: ''
+          element_label_colon: false
+          element_wrapper_type: ''
+          element_wrapper_class: ''
+          element_default_classes: true
+          empty: ''
+          hide_empty: false
+          empty_zero: false
+          hide_alter_empty: true
+          text: view
+          output_url_as_text: true
+          absolute: false
+          entity_type: eventseries
+          plugin_id: entity_link
+        view_eventinstance:
+          id: view_eventinstance
+          table: eventinstance
+          field: view_eventinstance
+          relationship: none
+          group_type: group
+          admin_label: ''
+          label: ''
+          exclude: true
+          alter:
+            alter_text: false
+            text: '{{ title }}'
+            make_link: false
+            path: ''
+            absolute: false
+            external: false
+            replace_spaces: false
+            path_case: none
+            trim_whitespace: false
+            alt: ''
+            rel: ''
+            link_class: ''
+            prefix: ''
+            suffix: ''
+            target: ''
+            nl2br: false
+            max_length: 0
+            word_boundary: true
+            ellipsis: true
+            more_link: false
+            more_link_text: ''
+            more_link_path: ''
+            strip_tags: false
+            trim: false
+            preserve_tags: ''
+            html: false
+          element_type: ''
+          element_class: ''
+          element_label_type: ''
+          element_label_class: ''
+          element_label_colon: false
+          element_wrapper_type: ''
+          element_wrapper_class: ''
+          element_default_classes: true
+          empty: ''
+          hide_empty: false
+          empty_zero: false
+          hide_alter_empty: true
+          text: ''
+          output_url_as_text: true
+          absolute: false
+          entity_type: eventinstance
+          plugin_id: entity_link
+        title_2:
+          id: title_2
+          table: eventseries_field_data
+          field: title
+          relationship: eventseries_id
+          group_type: group
+          admin_label: ''
+          label: 'Event Name'
+          exclude: false
+          alter:
+            alter_text: true
+            text: '{{ title }}'
+            make_link: true
+            path: '{{ view_eventinstance }}'
+            absolute: false
+            external: false
+            replace_spaces: false
+            path_case: none
+            trim_whitespace: false
+            alt: ''
+            rel: ''
+            link_class: ''
+            prefix: ''
+            suffix: ''
+            target: ''
+            nl2br: false
+            max_length: 0
+            word_boundary: true
+            ellipsis: true
+            more_link: false
+            more_link_text: ''
+            more_link_path: ''
+            strip_tags: false
+            trim: false
+            preserve_tags: ''
+            html: false
+          element_type: ''
+          element_class: ''
+          element_label_type: ''
+          element_label_class: ''
+          element_label_colon: true
+          element_wrapper_type: ''
+          element_wrapper_class: ''
+          element_default_classes: true
+          empty: ''
+          hide_empty: false
+          empty_zero: false
+          hide_alter_empty: true
+          click_sort_column: value
+          type: string
+          settings:
+            link_to_entity: false
+          group_column: value
+          group_columns: {  }
+          group_rows: true
+          delta_limit: 0
+          delta_offset: 0
+          delta_reversed: false
+          delta_first_last: false
+          multi_type: separator
+          separator: ', '
+          field_api_classes: false
+          entity_type: eventseries
+          entity_field: title
+          plugin_id: field
+        title_1:
+          id: title_1
+          table: eventseries_field_data
+          field: title
+          relationship: eventseries_id
+          group_type: group
+          admin_label: ''
+          label: Series
+          exclude: false
+          alter:
+            alter_text: true
+            text: '{{ "View Series"|t }}'
+            make_link: true
+            path: '{{ view_eventseries }}'
+            absolute: false
+            external: false
+            replace_spaces: false
+            path_case: none
+            trim_whitespace: false
+            alt: ''
+            rel: ''
+            link_class: ''
+            prefix: ''
+            suffix: ''
+            target: ''
+            nl2br: false
+            max_length: 0
+            word_boundary: true
+            ellipsis: true
+            more_link: false
+            more_link_text: ''
+            more_link_path: ''
+            strip_tags: false
+            trim: false
+            preserve_tags: ''
+            html: false
+          element_type: ''
+          element_class: ''
+          element_label_type: ''
+          element_label_class: ''
+          element_label_colon: true
+          element_wrapper_type: ''
+          element_wrapper_class: ''
+          element_default_classes: true
+          empty: ''
+          hide_empty: false
+          empty_zero: false
+          hide_alter_empty: true
+          click_sort_column: value
+          type: string
+          settings:
+            link_to_entity: true
+          group_column: value
+          group_columns: {  }
+          group_rows: true
+          delta_limit: 0
+          delta_offset: 0
+          delta_reversed: false
+          delta_first_last: false
+          multi_type: separator
+          separator: ', '
+          field_api_classes: false
+          entity_type: eventseries
+          entity_field: title
+          plugin_id: field
+        date__value:
+          id: date__value
+          table: eventinstance_field_data
+          field: date__value
+          relationship: none
+          group_type: group
+          admin_label: ''
+          label: 'Event Date'
+          exclude: false
+          alter:
+            alter_text: false
+            text: ''
+            make_link: false
+            path: ''
+            absolute: false
+            external: false
+            replace_spaces: false
+            path_case: none
+            trim_whitespace: false
+            alt: ''
+            rel: ''
+            link_class: ''
+            prefix: ''
+            suffix: ''
+            target: ''
+            nl2br: false
+            max_length: 0
+            word_boundary: true
+            ellipsis: true
+            more_link: false
+            more_link_text: ''
+            more_link_path: ''
+            strip_tags: false
+            trim: false
+            preserve_tags: ''
+            html: false
+          element_type: ''
+          element_class: ''
+          element_label_type: ''
+          element_label_class: ''
+          element_label_colon: true
+          element_wrapper_type: ''
+          element_wrapper_class: ''
+          element_default_classes: true
+          empty: ''
+          hide_empty: false
+          empty_zero: false
+          hide_alter_empty: true
+          click_sort_column: value
+          type: daterange_default
+          settings:
+            timezone_override: ''
+            format_type: medium
+            fromto: start_date
+            separator: '-'
+          group_column: value
+          group_columns: {  }
+          group_rows: true
+          delta_limit: 0
+          delta_offset: 0
+          delta_reversed: false
+          delta_first_last: false
+          multi_type: separator
+          separator: ', '
+          field_api_classes: false
+          entity_type: eventinstance
+          entity_field: date
+          plugin_id: field
+      defaults:
+        fields: false
+        filters: false
+        filter_groups: false
+        style: false
+        row: false
+      filters:
+        title:
+          id: title
+          table: eventseries_field_data
+          field: title
+          relationship: eventseries_id
+          group_type: group
+          admin_label: ''
+          operator: contains
+          value: ''
+          group: 1
+          exposed: true
+          expose:
+            operator_id: title_op
+            label: 'Event Name'
+            description: ''
+            use_operator: false
+            operator: title_op
+            identifier: title
+            required: false
+            remember: false
+            multiple: false
+            remember_roles:
+              authenticated: authenticated
+              anonymous: '0'
+              administrator: '0'
+            placeholder: ''
+            operator_limit_selection: false
+            operator_list: {  }
+          is_grouped: false
+          group_info:
+            label: ''
+            description: ''
+            identifier: ''
+            optional: true
+            widget: select
+            multiple: false
+            remember: false
+            default_group: All
+            default_group_multiple: {  }
+            group_items: {  }
+          entity_type: eventseries
+          entity_field: title
+          plugin_id: string
+        date__value:
+          id: date__value
+          table: eventinstance_field_data
+          field: date__value
+          relationship: none
+          group_type: group
+          admin_label: ''
+          operator: '>='
+          value:
+            min: ''
+            max: ''
+            value: ''
+            type: date
+          group: 1
+          exposed: true
+          expose:
+            operator_id: date__value_op
+            label: 'Date After'
+            description: ''
+            use_operator: false
+            operator: date__value_op
+            operator_limit_selection: false
+            operator_list: {  }
+            identifier: date__value
+            required: false
+            remember: false
+            multiple: false
+            remember_roles:
+              authenticated: authenticated
+              anonymous: '0'
+              administrator: '0'
+            placeholder: ''
+            min_placeholder: ''
+            max_placeholder: ''
+          is_grouped: false
+          group_info:
+            label: ''
+            description: ''
+            identifier: ''
+            optional: true
+            widget: select
+            multiple: false
+            remember: false
+            default_group: All
+            default_group_multiple: {  }
+            group_items: {  }
+          entity_type: eventinstance
+          entity_field: date
+          plugin_id: datetime
+        date__value_1:
+          id: date__value_1
+          table: eventinstance_field_data
+          field: date__value
+          relationship: none
+          group_type: group
+          admin_label: ''
+          operator: '<='
+          value:
+            min: ''
+            max: ''
+            value: ''
+            type: date
+          group: 1
+          exposed: true
+          expose:
+            operator_id: date__value_1_op
+            label: 'Date Before'
+            description: ''
+            use_operator: false
+            operator: date__value_1_op
+            operator_limit_selection: false
+            operator_list: {  }
+            identifier: date__value_1
+            required: false
+            remember: false
+            multiple: false
+            remember_roles:
+              authenticated: authenticated
+              anonymous: '0'
+              administrator: '0'
+            placeholder: ''
+            min_placeholder: ''
+            max_placeholder: ''
+          is_grouped: false
+          group_info:
+            label: ''
+            description: ''
+            identifier: ''
+            optional: true
+            widget: select
+            multiple: false
+            remember: false
+            default_group: All
+            default_group_multiple: {  }
+            group_items: {  }
+          entity_type: eventinstance
+          entity_field: date
+          plugin_id: datetime
+        status:
+          id: status
+          table: eventinstance_field_data
+          field: status
+          relationship: none
+          group_type: group
+          admin_label: ''
+          operator: '='
+          value: '1'
+          group: 1
+          exposed: false
+          expose:
+            operator_id: ''
+            label: ''
+            description: ''
+            use_operator: false
+            operator: ''
+            operator_limit_selection: false
+            operator_list: {  }
+            identifier: ''
+            required: false
+            remember: false
+            multiple: false
+            remember_roles:
+              authenticated: authenticated
+          is_grouped: false
+          group_info:
+            label: ''
+            description: ''
+            identifier: ''
+            optional: true
+            widget: select
+            multiple: false
+            remember: false
+            default_group: All
+            default_group_multiple: {  }
+            group_items: {  }
+          entity_type: eventinstance
+          entity_field: status
+          plugin_id: boolean
+        date__value_2:
+          id: date__value_2
+          table: eventinstance_field_data
+          field: date__value
+          relationship: none
+          group_type: group
+          admin_label: ''
+          operator: '>='
+          value:
+            min: ''
+            max: ''
+            value: today
+            type: offset
+          group: 1
+          exposed: false
+          expose:
+            operator_id: ''
+            label: ''
+            description: ''
+            use_operator: false
+            operator: ''
+            operator_limit_selection: false
+            operator_list: {  }
+            identifier: ''
+            required: false
+            remember: false
+            multiple: false
+            remember_roles:
+              authenticated: authenticated
+            placeholder: ''
+            min_placeholder: ''
+            max_placeholder: ''
+          is_grouped: false
+          group_info:
+            label: ''
+            description: ''
+            identifier: ''
+            optional: true
+            widget: select
+            multiple: false
+            remember: false
+            default_group: All
+            default_group_multiple: {  }
+            group_items: {  }
+          entity_type: eventinstance
+          entity_field: date
+          plugin_id: datetime
+      filter_groups:
+        operator: AND
+        groups:
+          1: AND
+      style:
+        type: default
+        options:
+          row_class: ''
+          default_row_class: true
+          uses_fields: false
+      row:
+        type: 'entity:eventinstance'
+        options:
+          relationship: none
+          view_mode: list
+    cache_metadata:
+      max-age: -1
+      contexts:
+        - 'languages:language_content'
+        - 'languages:language_interface'
+        - url
+        - url.query_args
+        - user.permissions
+      tags: {  }
diff --git a/modules/recurring_events_views/config/optional/views.view.registrations.yml b/modules/recurring_events_views/config/optional/views.view.registrations.yml
new file mode 100644
index 0000000000000000000000000000000000000000..289190adf2153616e97e5628bd4a12be6d50b2b1
--- /dev/null
+++ b/modules/recurring_events_views/config/optional/views.view.registrations.yml
@@ -0,0 +1,2515 @@
+langcode: en
+status: true
+dependencies:
+  module:
+    - datetime
+    - datetime_range
+    - recurring_events
+    - recurring_events_registration
+    - user
+id: registrations
+label: Registrations
+module: views
+description: 'A view showing all the registrants on the site'
+tag: ''
+base_table: registrant
+base_field: id
+display:
+  default:
+    display_plugin: default
+    id: default
+    display_title: Master
+    position: 0
+    display_options:
+      access:
+        type: perm
+        options:
+          perm: 'access registrant overview'
+      cache:
+        type: tag
+        options: {  }
+      query:
+        type: views_query
+        options:
+          disable_sql_rewrite: false
+          distinct: false
+          replica: false
+          query_comment: ''
+          query_tags: {  }
+      exposed_form:
+        type: basic
+        options:
+          submit_button: Apply
+          reset_button: false
+          reset_button_label: Reset
+          exposed_sorts_label: 'Sort by'
+          expose_sort_order: true
+          sort_asc_label: Asc
+          sort_desc_label: Desc
+      pager:
+        type: full
+        options:
+          items_per_page: 25
+          offset: 0
+          id: 0
+          total_pages: null
+          tags:
+            previous: ‹‹
+            next: ››
+            first: '« First'
+            last: 'Last »'
+          expose:
+            items_per_page: false
+            items_per_page_label: 'Items per page'
+            items_per_page_options: '5, 10, 25, 50'
+            items_per_page_options_all: false
+            items_per_page_options_all_label: '- All -'
+            offset: false
+            offset_label: Offset
+          quantity: 9
+      style:
+        type: table
+      row:
+        type: fields
+      fields:
+        title:
+          id: title
+          table: eventseries_field_data
+          field: title
+          relationship: eventseries_id
+          group_type: group
+          admin_label: ''
+          label: ''
+          exclude: true
+          alter:
+            alter_text: false
+            text: ''
+            make_link: false
+            path: ''
+            absolute: false
+            external: false
+            replace_spaces: false
+            path_case: none
+            trim_whitespace: false
+            alt: ''
+            rel: ''
+            link_class: ''
+            prefix: ''
+            suffix: ''
+            target: ''
+            nl2br: false
+            max_length: 0
+            word_boundary: true
+            ellipsis: true
+            more_link: false
+            more_link_text: ''
+            more_link_path: ''
+            strip_tags: false
+            trim: false
+            preserve_tags: ''
+            html: false
+          element_type: ''
+          element_class: ''
+          element_label_type: ''
+          element_label_class: ''
+          element_label_colon: false
+          element_wrapper_type: ''
+          element_wrapper_class: ''
+          element_default_classes: true
+          empty: ''
+          hide_empty: false
+          empty_zero: false
+          hide_alter_empty: true
+          click_sort_column: value
+          type: string
+          settings:
+            link_to_entity: false
+          group_column: value
+          group_columns: {  }
+          group_rows: true
+          delta_limit: 0
+          delta_offset: 0
+          delta_reversed: false
+          delta_first_last: false
+          multi_type: separator
+          separator: ', '
+          field_api_classes: false
+          entity_type: eventseries
+          entity_field: title
+          plugin_id: field
+        view_eventinstance:
+          id: view_eventinstance
+          table: eventinstance
+          field: view_eventinstance
+          relationship: eventinstance_id
+          group_type: group
+          admin_label: ''
+          label: ''
+          exclude: true
+          alter:
+            alter_text: false
+            text: ''
+            make_link: false
+            path: ''
+            absolute: false
+            external: false
+            replace_spaces: false
+            path_case: none
+            trim_whitespace: false
+            alt: ''
+            rel: ''
+            link_class: ''
+            prefix: ''
+            suffix: ''
+            target: ''
+            nl2br: false
+            max_length: 0
+            word_boundary: true
+            ellipsis: true
+            more_link: false
+            more_link_text: ''
+            more_link_path: ''
+            strip_tags: false
+            trim: false
+            preserve_tags: ''
+            html: false
+          element_type: ''
+          element_class: ''
+          element_label_type: ''
+          element_label_class: ''
+          element_label_colon: false
+          element_wrapper_type: ''
+          element_wrapper_class: ''
+          element_default_classes: true
+          empty: ''
+          hide_empty: false
+          empty_zero: false
+          hide_alter_empty: true
+          text: view
+          output_url_as_text: true
+          absolute: false
+          entity_type: eventinstance
+          plugin_id: entity_link
+        view_eventseries:
+          id: view_eventseries
+          table: eventseries
+          field: view_eventseries
+          relationship: eventseries_id
+          group_type: group
+          admin_label: ''
+          label: ''
+          exclude: true
+          alter:
+            alter_text: false
+            text: ''
+            make_link: false
+            path: ''
+            absolute: false
+            external: false
+            replace_spaces: false
+            path_case: none
+            trim_whitespace: false
+            alt: ''
+            rel: ''
+            link_class: ''
+            prefix: ''
+            suffix: ''
+            target: ''
+            nl2br: false
+            max_length: 0
+            word_boundary: true
+            ellipsis: true
+            more_link: false
+            more_link_text: ''
+            more_link_path: ''
+            strip_tags: false
+            trim: false
+            preserve_tags: ''
+            html: false
+          element_type: ''
+          element_class: ''
+          element_label_type: ''
+          element_label_class: ''
+          element_label_colon: false
+          element_wrapper_type: ''
+          element_wrapper_class: ''
+          element_default_classes: true
+          empty: ''
+          hide_empty: false
+          empty_zero: false
+          hide_alter_empty: true
+          text: view
+          output_url_as_text: true
+          absolute: false
+          entity_type: eventseries
+          plugin_id: entity_link
+        id:
+          id: id
+          table: registrant
+          field: id
+          relationship: none
+          group_type: group
+          admin_label: ''
+          label: ID
+          exclude: false
+          alter:
+            alter_text: false
+            text: ''
+            make_link: false
+            path: ''
+            absolute: false
+            external: false
+            replace_spaces: false
+            path_case: none
+            trim_whitespace: false
+            alt: ''
+            rel: ''
+            link_class: ''
+            prefix: ''
+            suffix: ''
+            target: ''
+            nl2br: false
+            max_length: 0
+            word_boundary: true
+            ellipsis: true
+            more_link: false
+            more_link_text: ''
+            more_link_path: ''
+            strip_tags: false
+            trim: false
+            preserve_tags: ''
+            html: false
+          element_type: ''
+          element_class: ''
+          element_label_type: ''
+          element_label_class: ''
+          element_label_colon: true
+          element_wrapper_type: ''
+          element_wrapper_class: ''
+          element_default_classes: true
+          empty: ''
+          hide_empty: false
+          empty_zero: false
+          hide_alter_empty: true
+          click_sort_column: value
+          type: number_integer
+          settings:
+            thousand_separator: ''
+            prefix_suffix: true
+          group_column: value
+          group_columns: {  }
+          group_rows: true
+          delta_limit: 0
+          delta_offset: 0
+          delta_reversed: false
+          delta_first_last: false
+          multi_type: separator
+          separator: ', '
+          field_api_classes: false
+          entity_type: registrant
+          entity_field: id
+          plugin_id: field
+        title_1:
+          id: title_1
+          table: eventseries_field_data
+          field: title
+          relationship: eventseries_id
+          group_type: group
+          admin_label: ''
+          label: 'Event Series'
+          exclude: false
+          alter:
+            alter_text: true
+            text: '{{ title }}'
+            make_link: true
+            path: '{{ view_eventseries }}'
+            absolute: false
+            external: false
+            replace_spaces: false
+            path_case: none
+            trim_whitespace: false
+            alt: ''
+            rel: ''
+            link_class: ''
+            prefix: ''
+            suffix: ''
+            target: ''
+            nl2br: false
+            max_length: 0
+            word_boundary: true
+            ellipsis: true
+            more_link: false
+            more_link_text: ''
+            more_link_path: ''
+            strip_tags: false
+            trim: false
+            preserve_tags: ''
+            html: false
+          element_type: ''
+          element_class: ''
+          element_label_type: ''
+          element_label_class: ''
+          element_label_colon: true
+          element_wrapper_type: ''
+          element_wrapper_class: ''
+          element_default_classes: true
+          empty: ''
+          hide_empty: false
+          empty_zero: false
+          hide_alter_empty: true
+          click_sort_column: value
+          type: string
+          settings:
+            link_to_entity: false
+          group_column: value
+          group_columns: {  }
+          group_rows: true
+          delta_limit: 0
+          delta_offset: 0
+          delta_reversed: false
+          delta_first_last: false
+          multi_type: separator
+          separator: ', '
+          field_api_classes: false
+          entity_type: eventseries
+          entity_field: title
+          plugin_id: field
+        date__value:
+          id: date__value
+          table: eventinstance_field_data
+          field: date__value
+          relationship: eventinstance_id
+          group_type: group
+          admin_label: ''
+          label: 'Event Date'
+          exclude: false
+          alter:
+            alter_text: true
+            text: '{{ date__value }}'
+            make_link: true
+            path: '{{ view_eventinstance }}'
+            absolute: false
+            external: false
+            replace_spaces: false
+            path_case: none
+            trim_whitespace: false
+            alt: ''
+            rel: ''
+            link_class: ''
+            prefix: ''
+            suffix: ''
+            target: ''
+            nl2br: false
+            max_length: 0
+            word_boundary: true
+            ellipsis: true
+            more_link: false
+            more_link_text: ''
+            more_link_path: ''
+            strip_tags: false
+            trim: false
+            preserve_tags: ''
+            html: false
+          element_type: ''
+          element_class: ''
+          element_label_type: ''
+          element_label_class: ''
+          element_label_colon: true
+          element_wrapper_type: ''
+          element_wrapper_class: ''
+          element_default_classes: true
+          empty: ''
+          hide_empty: false
+          empty_zero: false
+          hide_alter_empty: true
+          click_sort_column: value
+          type: daterange_default
+          settings:
+            timezone_override: ''
+            format_type: medium
+            fromto: start_date
+            separator: '-'
+          group_column: value
+          group_columns: {  }
+          group_rows: true
+          delta_limit: 0
+          delta_offset: 0
+          delta_reversed: false
+          delta_first_last: false
+          multi_type: separator
+          separator: ', '
+          field_api_classes: false
+          entity_type: eventinstance
+          entity_field: date
+          plugin_id: field
+        waitlist:
+          id: waitlist
+          table: registrant
+          field: waitlist
+          relationship: none
+          group_type: group
+          admin_label: ''
+          label: Waitlist
+          exclude: false
+          alter:
+            alter_text: false
+            text: ''
+            make_link: false
+            path: ''
+            absolute: false
+            external: false
+            replace_spaces: false
+            path_case: none
+            trim_whitespace: false
+            alt: ''
+            rel: ''
+            link_class: ''
+            prefix: ''
+            suffix: ''
+            target: ''
+            nl2br: false
+            max_length: 0
+            word_boundary: true
+            ellipsis: true
+            more_link: false
+            more_link_text: ''
+            more_link_path: ''
+            strip_tags: false
+            trim: false
+            preserve_tags: ''
+            html: false
+          element_type: ''
+          element_class: ''
+          element_label_type: ''
+          element_label_class: ''
+          element_label_colon: true
+          element_wrapper_type: ''
+          element_wrapper_class: ''
+          element_default_classes: true
+          empty: ''
+          hide_empty: false
+          empty_zero: false
+          hide_alter_empty: true
+          click_sort_column: value
+          type: boolean
+          settings:
+            format: yes-no
+            format_custom_true: ''
+            format_custom_false: ''
+          group_column: value
+          group_columns: {  }
+          group_rows: true
+          delta_limit: 0
+          delta_offset: 0
+          delta_reversed: false
+          delta_first_last: false
+          multi_type: separator
+          separator: ', '
+          field_api_classes: false
+          entity_type: registrant
+          entity_field: waitlist
+          plugin_id: field
+        type:
+          id: type
+          table: registrant
+          field: type
+          relationship: none
+          group_type: group
+          admin_label: ''
+          label: Type
+          exclude: false
+          alter:
+            alter_text: false
+            text: ''
+            make_link: false
+            path: ''
+            absolute: false
+            external: false
+            replace_spaces: false
+            path_case: none
+            trim_whitespace: false
+            alt: ''
+            rel: ''
+            link_class: ''
+            prefix: ''
+            suffix: ''
+            target: ''
+            nl2br: false
+            max_length: 0
+            word_boundary: true
+            ellipsis: true
+            more_link: false
+            more_link_text: ''
+            more_link_path: ''
+            strip_tags: false
+            trim: false
+            preserve_tags: ''
+            html: false
+          element_type: ''
+          element_class: ''
+          element_label_type: ''
+          element_label_class: ''
+          element_label_colon: true
+          element_wrapper_type: ''
+          element_wrapper_class: ''
+          element_default_classes: true
+          empty: ''
+          hide_empty: false
+          empty_zero: false
+          hide_alter_empty: true
+          click_sort_column: value
+          type: string
+          settings:
+            link_to_entity: false
+          group_column: value
+          group_columns: {  }
+          group_rows: true
+          delta_limit: 0
+          delta_offset: 0
+          delta_reversed: false
+          delta_first_last: false
+          multi_type: separator
+          separator: ', '
+          field_api_classes: false
+          entity_type: registrant
+          entity_field: type
+          plugin_id: field
+        bundle:
+          id: bundle
+          table: registrant
+          field: bundle
+          relationship: none
+          group_type: group
+          admin_label: ''
+          label: Bundle
+          exclude: false
+          alter:
+            alter_text: false
+            text: ''
+            make_link: false
+            path: ''
+            absolute: false
+            external: false
+            replace_spaces: false
+            path_case: none
+            trim_whitespace: false
+            alt: ''
+            rel: ''
+            link_class: ''
+            prefix: ''
+            suffix: ''
+            target: ''
+            nl2br: false
+            max_length: 0
+            word_boundary: true
+            ellipsis: true
+            more_link: false
+            more_link_text: ''
+            more_link_path: ''
+            strip_tags: false
+            trim: false
+            preserve_tags: ''
+            html: false
+          element_type: ''
+          element_class: ''
+          element_label_type: ''
+          element_label_class: ''
+          element_label_colon: true
+          element_wrapper_type: ''
+          element_wrapper_class: ''
+          element_default_classes: true
+          empty: ''
+          hide_empty: false
+          empty_zero: false
+          hide_alter_empty: true
+          click_sort_column: target_id
+          type: entity_reference_label
+          settings:
+            link: false
+          group_column: target_id
+          group_columns: {  }
+          group_rows: true
+          delta_limit: 0
+          delta_offset: 0
+          delta_reversed: false
+          delta_first_last: false
+          multi_type: separator
+          separator: ', '
+          field_api_classes: false
+          entity_type: registrant
+          entity_field: bundle
+          plugin_id: field
+        user_id:
+          id: user_id
+          table: registrant
+          field: user_id
+          relationship: none
+          group_type: group
+          admin_label: ''
+          label: Author
+          exclude: false
+          alter:
+            alter_text: false
+            text: ''
+            make_link: false
+            path: ''
+            absolute: false
+            external: false
+            replace_spaces: false
+            path_case: none
+            trim_whitespace: false
+            alt: ''
+            rel: ''
+            link_class: ''
+            prefix: ''
+            suffix: ''
+            target: ''
+            nl2br: false
+            max_length: 0
+            word_boundary: true
+            ellipsis: true
+            more_link: false
+            more_link_text: ''
+            more_link_path: ''
+            strip_tags: false
+            trim: false
+            preserve_tags: ''
+            html: false
+          element_type: ''
+          element_class: ''
+          element_label_type: ''
+          element_label_class: ''
+          element_label_colon: true
+          element_wrapper_type: ''
+          element_wrapper_class: ''
+          element_default_classes: true
+          empty: ''
+          hide_empty: false
+          empty_zero: false
+          hide_alter_empty: true
+          click_sort_column: target_id
+          type: entity_reference_label
+          settings:
+            link: true
+          group_column: target_id
+          group_columns: {  }
+          group_rows: true
+          delta_limit: 0
+          delta_offset: 0
+          delta_reversed: false
+          delta_first_last: false
+          multi_type: separator
+          separator: ', '
+          field_api_classes: false
+          entity_type: registrant
+          entity_field: user_id
+          plugin_id: field
+        operations:
+          id: operations
+          table: registrant
+          field: operations
+          relationship: none
+          group_type: group
+          admin_label: ''
+          label: Operations
+          exclude: false
+          alter:
+            alter_text: false
+            text: ''
+            make_link: false
+            path: ''
+            absolute: false
+            external: false
+            replace_spaces: false
+            path_case: none
+            trim_whitespace: false
+            alt: ''
+            rel: ''
+            link_class: ''
+            prefix: ''
+            suffix: ''
+            target: ''
+            nl2br: false
+            max_length: 0
+            word_boundary: true
+            ellipsis: true
+            more_link: false
+            more_link_text: ''
+            more_link_path: ''
+            strip_tags: false
+            trim: false
+            preserve_tags: ''
+            html: false
+          element_type: ''
+          element_class: ''
+          element_label_type: ''
+          element_label_class: ''
+          element_label_colon: true
+          element_wrapper_type: ''
+          element_wrapper_class: ''
+          element_default_classes: true
+          empty: ''
+          hide_empty: false
+          empty_zero: false
+          hide_alter_empty: true
+          destination: false
+          entity_type: registrant
+          plugin_id: entity_operations
+      filters:
+        title:
+          id: title
+          table: eventseries_field_data
+          field: title
+          relationship: eventseries_id
+          group_type: group
+          admin_label: ''
+          operator: contains
+          value: ''
+          group: 1
+          exposed: true
+          expose:
+            operator_id: title_op
+            label: 'Event Name'
+            description: ''
+            use_operator: false
+            operator: title_op
+            identifier: title
+            required: false
+            remember: false
+            multiple: false
+            remember_roles:
+              authenticated: authenticated
+              anonymous: '0'
+              administrator: '0'
+            placeholder: ''
+            operator_limit_selection: false
+            operator_list: {  }
+          is_grouped: false
+          group_info:
+            label: ''
+            description: ''
+            identifier: ''
+            optional: true
+            widget: select
+            multiple: false
+            remember: false
+            default_group: All
+            default_group_multiple: {  }
+            group_items: {  }
+          entity_type: eventseries
+          entity_field: title
+          plugin_id: string
+        waitlist:
+          id: waitlist
+          table: registrant
+          field: waitlist
+          relationship: none
+          group_type: group
+          admin_label: ''
+          operator: '='
+          value: All
+          group: 1
+          exposed: true
+          expose:
+            operator_id: ''
+            label: Waitlist
+            description: ''
+            use_operator: false
+            operator: waitlist_op
+            identifier: waitlist
+            required: false
+            remember: false
+            multiple: false
+            remember_roles:
+              authenticated: authenticated
+              anonymous: '0'
+              administrator: '0'
+            operator_limit_selection: false
+            operator_list: {  }
+          is_grouped: false
+          group_info:
+            label: ''
+            description: ''
+            identifier: ''
+            optional: true
+            widget: select
+            multiple: false
+            remember: false
+            default_group: All
+            default_group_multiple: {  }
+            group_items: {  }
+          entity_type: registrant
+          entity_field: waitlist
+          plugin_id: boolean
+        type:
+          id: type
+          table: registrant
+          field: type
+          relationship: none
+          group_type: group
+          admin_label: ''
+          operator: contains
+          value: ''
+          group: 1
+          exposed: true
+          expose:
+            operator_id: type_op
+            label: Type
+            description: ''
+            use_operator: false
+            operator: type_op
+            identifier: type
+            required: false
+            remember: false
+            multiple: false
+            remember_roles:
+              authenticated: authenticated
+              anonymous: '0'
+              administrator: '0'
+            placeholder: ''
+            operator_limit_selection: false
+            operator_list: {  }
+          is_grouped: false
+          group_info:
+            label: ''
+            description: ''
+            identifier: ''
+            optional: true
+            widget: select
+            multiple: false
+            remember: false
+            default_group: All
+            default_group_multiple: {  }
+            group_items: {  }
+          entity_type: registrant
+          entity_field: type
+          plugin_id: string
+        bundle:
+          id: bundle
+          table: registrant
+          field: bundle
+          relationship: none
+          group_type: group
+          admin_label: ''
+          operator: in
+          value: {  }
+          group: 1
+          exposed: true
+          expose:
+            operator_id: bundle_op
+            label: Bundle
+            description: ''
+            use_operator: false
+            operator: bundle_op
+            identifier: bundle
+            required: false
+            remember: false
+            multiple: false
+            remember_roles:
+              authenticated: authenticated
+              anonymous: '0'
+              administrator: '0'
+            reduce: false
+            operator_limit_selection: false
+            operator_list: {  }
+          is_grouped: false
+          group_info:
+            label: ''
+            description: ''
+            identifier: ''
+            optional: true
+            widget: select
+            multiple: false
+            remember: false
+            default_group: All
+            default_group_multiple: {  }
+            group_items: {  }
+          entity_type: registrant
+          entity_field: bundle
+          plugin_id: bundle
+        created_1:
+          id: created_1
+          table: registrant
+          field: created
+          relationship: none
+          group_type: group
+          admin_label: ''
+          operator: '<='
+          value:
+            min: ''
+            max: ''
+            value: ''
+            type: date
+          group: 1
+          exposed: true
+          expose:
+            operator_id: created_1_op
+            label: 'Created Before'
+            description: ''
+            use_operator: false
+            operator: created_1_op
+            identifier: created_1
+            required: false
+            remember: false
+            multiple: false
+            remember_roles:
+              authenticated: authenticated
+              anonymous: '0'
+              administrator: '0'
+            placeholder: ''
+            min_placeholder: ''
+            max_placeholder: ''
+            operator_limit_selection: false
+            operator_list: {  }
+          is_grouped: false
+          group_info:
+            label: ''
+            description: ''
+            identifier: ''
+            optional: true
+            widget: select
+            multiple: false
+            remember: false
+            default_group: All
+            default_group_multiple: {  }
+            group_items: {  }
+          entity_type: registrant
+          entity_field: created
+          plugin_id: date
+        created_2:
+          id: created_2
+          table: registrant
+          field: created
+          relationship: none
+          group_type: group
+          admin_label: ''
+          operator: '>='
+          value:
+            min: ''
+            max: ''
+            value: ''
+            type: date
+          group: 1
+          exposed: true
+          expose:
+            operator_id: created_2_op
+            label: 'Created After'
+            description: ''
+            use_operator: false
+            operator: created_2_op
+            identifier: created_2
+            required: false
+            remember: false
+            multiple: false
+            remember_roles:
+              authenticated: authenticated
+              anonymous: '0'
+              administrator: '0'
+            placeholder: ''
+            min_placeholder: ''
+            max_placeholder: ''
+            operator_limit_selection: false
+            operator_list: {  }
+          is_grouped: false
+          group_info:
+            label: ''
+            description: ''
+            identifier: ''
+            optional: true
+            widget: select
+            multiple: false
+            remember: false
+            default_group: All
+            default_group_multiple: {  }
+            group_items: {  }
+          entity_type: registrant
+          entity_field: created
+          plugin_id: date
+        uid:
+          id: uid
+          table: users_field_data
+          field: uid
+          relationship: user_id
+          group_type: group
+          admin_label: ''
+          operator: in
+          value: {  }
+          group: 1
+          exposed: true
+          expose:
+            operator_id: uid_op
+            label: Author
+            description: ''
+            use_operator: false
+            operator: uid_op
+            identifier: uid
+            required: false
+            remember: false
+            multiple: false
+            remember_roles:
+              authenticated: authenticated
+              anonymous: '0'
+              administrator: '0'
+            reduce: false
+            operator_limit_selection: false
+            operator_list: {  }
+          is_grouped: false
+          group_info:
+            label: ''
+            description: ''
+            identifier: ''
+            optional: true
+            widget: select
+            multiple: false
+            remember: false
+            default_group: All
+            default_group_multiple: {  }
+            group_items: {  }
+          entity_type: user
+          entity_field: uid
+          plugin_id: user_name
+      sorts: {  }
+      title: Registrations
+      header: {  }
+      footer: {  }
+      empty:
+        area:
+          id: area
+          table: views
+          field: area
+          relationship: none
+          group_type: group
+          admin_label: ''
+          empty: true
+          tokenize: false
+          content:
+            value: '<h2>No registrations found</h2>'
+            format: basic_html
+          plugin_id: text
+      relationships:
+        eventinstance_id:
+          id: eventinstance_id
+          table: registrant
+          field: eventinstance_id
+          relationship: none
+          group_type: group
+          admin_label: 'Event Instance entity'
+          required: false
+          entity_type: registrant
+          entity_field: eventinstance_id
+          plugin_id: standard
+        eventseries_id:
+          id: eventseries_id
+          table: registrant
+          field: eventseries_id
+          relationship: none
+          group_type: group
+          admin_label: 'Event series entity'
+          required: false
+          entity_type: registrant
+          entity_field: eventseries_id
+          plugin_id: standard
+        user_id:
+          id: user_id
+          table: registrant
+          field: user_id
+          relationship: none
+          group_type: group
+          admin_label: User
+          required: false
+          entity_type: registrant
+          entity_field: user_id
+          plugin_id: standard
+      arguments: {  }
+      display_extenders: {  }
+      filter_groups:
+        operator: AND
+        groups:
+          1: AND
+    cache_metadata:
+      max-age: -1
+      contexts:
+        - 'languages:language_content'
+        - 'languages:language_interface'
+        - url
+        - url.query_args
+        - user.permissions
+      tags: {  }
+  admin_page:
+    display_plugin: page
+    id: admin_page
+    display_title: Page
+    position: 1
+    display_options:
+      display_extenders: {  }
+      path: admin/content/events/registrations
+    cache_metadata:
+      max-age: -1
+      contexts:
+        - 'languages:language_content'
+        - 'languages:language_interface'
+        - url
+        - url.query_args
+        - user.permissions
+      tags: {  }
+  event_registrant_list:
+    display_plugin: page
+    id: event_registrant_list
+    display_title: Page
+    position: 1
+    display_options:
+      display_extenders: {  }
+      path: events/%eventinstance/registrations
+      defaults:
+        access: false
+        arguments: false
+        filters: false
+        filter_groups: false
+        fields: false
+        sorts: false
+      arguments: {  }
+      filters:
+        waitlist:
+          id: waitlist
+          table: registrant
+          field: waitlist
+          relationship: none
+          group_type: group
+          admin_label: ''
+          operator: '='
+          value: All
+          group: 1
+          exposed: true
+          expose:
+            operator_id: ''
+            label: Waitlist
+            description: ''
+            use_operator: false
+            operator: waitlist_op
+            identifier: waitlist
+            required: false
+            remember: false
+            multiple: false
+            remember_roles:
+              authenticated: authenticated
+              anonymous: '0'
+              administrator: '0'
+            operator_limit_selection: false
+            operator_list: {  }
+          is_grouped: false
+          group_info:
+            label: ''
+            description: ''
+            identifier: ''
+            optional: true
+            widget: select
+            multiple: false
+            remember: false
+            default_group: All
+            default_group_multiple: {  }
+            group_items: {  }
+          entity_type: registrant
+          entity_field: waitlist
+          plugin_id: boolean
+        created_1:
+          id: created_1
+          table: registrant
+          field: created
+          relationship: none
+          group_type: group
+          admin_label: ''
+          operator: '<='
+          value:
+            min: ''
+            max: ''
+            value: ''
+            type: date
+          group: 1
+          exposed: true
+          expose:
+            operator_id: created_1_op
+            label: 'Created Before'
+            description: ''
+            use_operator: false
+            operator: created_1_op
+            identifier: created_1
+            required: false
+            remember: false
+            multiple: false
+            remember_roles:
+              authenticated: authenticated
+              anonymous: '0'
+              administrator: '0'
+            placeholder: ''
+            min_placeholder: ''
+            max_placeholder: ''
+            operator_limit_selection: false
+            operator_list: {  }
+          is_grouped: false
+          group_info:
+            label: ''
+            description: ''
+            identifier: ''
+            optional: true
+            widget: select
+            multiple: false
+            remember: false
+            default_group: All
+            default_group_multiple: {  }
+            group_items: {  }
+          entity_type: registrant
+          entity_field: created
+          plugin_id: date
+        created_2:
+          id: created_2
+          table: registrant
+          field: created
+          relationship: none
+          group_type: group
+          admin_label: ''
+          operator: '>='
+          value:
+            min: ''
+            max: ''
+            value: ''
+            type: date
+          group: 1
+          exposed: true
+          expose:
+            operator_id: created_2_op
+            label: 'Created After'
+            description: ''
+            use_operator: false
+            operator: created_2_op
+            identifier: created_2
+            required: false
+            remember: false
+            multiple: false
+            remember_roles:
+              authenticated: authenticated
+              anonymous: '0'
+              administrator: '0'
+            placeholder: ''
+            min_placeholder: ''
+            max_placeholder: ''
+            operator_limit_selection: false
+            operator_list: {  }
+          is_grouped: false
+          group_info:
+            label: ''
+            description: ''
+            identifier: ''
+            optional: true
+            widget: select
+            multiple: false
+            remember: false
+            default_group: All
+            default_group_multiple: {  }
+            group_items: {  }
+          entity_type: registrant
+          entity_field: created
+          plugin_id: date
+        uid:
+          id: uid
+          table: users_field_data
+          field: uid
+          relationship: user_id
+          group_type: group
+          admin_label: ''
+          operator: in
+          value: {  }
+          group: 1
+          exposed: true
+          expose:
+            operator_id: uid_op
+            label: Author
+            description: ''
+            use_operator: false
+            operator: uid_op
+            identifier: uid
+            required: false
+            remember: false
+            multiple: false
+            remember_roles:
+              authenticated: authenticated
+              anonymous: '0'
+              administrator: '0'
+            reduce: false
+            operator_limit_selection: false
+            operator_list: {  }
+          is_grouped: false
+          group_info:
+            label: ''
+            description: ''
+            identifier: ''
+            optional: true
+            widget: select
+            multiple: false
+            remember: false
+            default_group: All
+            default_group_multiple: {  }
+            group_items: {  }
+          entity_type: user
+          entity_field: uid
+          plugin_id: user_name
+      filter_groups:
+        operator: AND
+        groups:
+          1: AND
+      fields:
+        id:
+          id: id
+          table: registrant
+          field: id
+          relationship: none
+          group_type: group
+          admin_label: ''
+          label: ID
+          exclude: false
+          alter:
+            alter_text: false
+            text: ''
+            make_link: false
+            path: ''
+            absolute: false
+            external: false
+            replace_spaces: false
+            path_case: none
+            trim_whitespace: false
+            alt: ''
+            rel: ''
+            link_class: ''
+            prefix: ''
+            suffix: ''
+            target: ''
+            nl2br: false
+            max_length: 0
+            word_boundary: true
+            ellipsis: true
+            more_link: false
+            more_link_text: ''
+            more_link_path: ''
+            strip_tags: false
+            trim: false
+            preserve_tags: ''
+            html: false
+          element_type: ''
+          element_class: ''
+          element_label_type: ''
+          element_label_class: ''
+          element_label_colon: true
+          element_wrapper_type: ''
+          element_wrapper_class: ''
+          element_default_classes: true
+          empty: ''
+          hide_empty: false
+          empty_zero: false
+          hide_alter_empty: true
+          click_sort_column: value
+          type: number_integer
+          settings:
+            thousand_separator: ''
+            prefix_suffix: true
+          group_column: value
+          group_columns: {  }
+          group_rows: true
+          delta_limit: 0
+          delta_offset: 0
+          delta_reversed: false
+          delta_first_last: false
+          multi_type: separator
+          separator: ', '
+          field_api_classes: false
+          entity_type: registrant
+          entity_field: id
+          plugin_id: field
+        waitlist:
+          id: waitlist
+          table: registrant
+          field: waitlist
+          relationship: none
+          group_type: group
+          admin_label: ''
+          label: Waitlist
+          exclude: false
+          alter:
+            alter_text: false
+            text: ''
+            make_link: false
+            path: ''
+            absolute: false
+            external: false
+            replace_spaces: false
+            path_case: none
+            trim_whitespace: false
+            alt: ''
+            rel: ''
+            link_class: ''
+            prefix: ''
+            suffix: ''
+            target: ''
+            nl2br: false
+            max_length: 0
+            word_boundary: true
+            ellipsis: true
+            more_link: false
+            more_link_text: ''
+            more_link_path: ''
+            strip_tags: false
+            trim: false
+            preserve_tags: ''
+            html: false
+          element_type: ''
+          element_class: ''
+          element_label_type: ''
+          element_label_class: ''
+          element_label_colon: true
+          element_wrapper_type: ''
+          element_wrapper_class: ''
+          element_default_classes: true
+          empty: ''
+          hide_empty: false
+          empty_zero: false
+          hide_alter_empty: true
+          click_sort_column: value
+          type: boolean
+          settings:
+            format: yes-no
+            format_custom_true: ''
+            format_custom_false: ''
+          group_column: value
+          group_columns: {  }
+          group_rows: true
+          delta_limit: 0
+          delta_offset: 0
+          delta_reversed: false
+          delta_first_last: false
+          multi_type: separator
+          separator: ', '
+          field_api_classes: false
+          entity_type: registrant
+          entity_field: waitlist
+          plugin_id: field
+        user_id:
+          id: user_id
+          table: registrant
+          field: user_id
+          relationship: none
+          group_type: group
+          admin_label: ''
+          label: Author
+          exclude: false
+          alter:
+            alter_text: false
+            text: ''
+            make_link: false
+            path: ''
+            absolute: false
+            external: false
+            replace_spaces: false
+            path_case: none
+            trim_whitespace: false
+            alt: ''
+            rel: ''
+            link_class: ''
+            prefix: ''
+            suffix: ''
+            target: ''
+            nl2br: false
+            max_length: 0
+            word_boundary: true
+            ellipsis: true
+            more_link: false
+            more_link_text: ''
+            more_link_path: ''
+            strip_tags: false
+            trim: false
+            preserve_tags: ''
+            html: false
+          element_type: ''
+          element_class: ''
+          element_label_type: ''
+          element_label_class: ''
+          element_label_colon: true
+          element_wrapper_type: ''
+          element_wrapper_class: ''
+          element_default_classes: true
+          empty: ''
+          hide_empty: false
+          empty_zero: false
+          hide_alter_empty: true
+          click_sort_column: target_id
+          type: entity_reference_label
+          settings:
+            link: true
+          group_column: target_id
+          group_columns: {  }
+          group_rows: true
+          delta_limit: 0
+          delta_offset: 0
+          delta_reversed: false
+          delta_first_last: false
+          multi_type: separator
+          separator: ', '
+          field_api_classes: false
+          entity_type: registrant
+          entity_field: user_id
+          plugin_id: field
+        operations:
+          id: operations
+          table: registrant
+          field: operations
+          relationship: none
+          group_type: group
+          admin_label: ''
+          label: Operations
+          exclude: false
+          alter:
+            alter_text: false
+            text: ''
+            make_link: false
+            path: ''
+            absolute: false
+            external: false
+            replace_spaces: false
+            path_case: none
+            trim_whitespace: false
+            alt: ''
+            rel: ''
+            link_class: ''
+            prefix: ''
+            suffix: ''
+            target: ''
+            nl2br: false
+            max_length: 0
+            word_boundary: true
+            ellipsis: true
+            more_link: false
+            more_link_text: ''
+            more_link_path: ''
+            strip_tags: false
+            trim: false
+            preserve_tags: ''
+            html: false
+          element_type: ''
+          element_class: ''
+          element_label_type: ''
+          element_label_class: ''
+          element_label_colon: true
+          element_wrapper_type: ''
+          element_wrapper_class: ''
+          element_default_classes: true
+          empty: ''
+          hide_empty: false
+          empty_zero: false
+          hide_alter_empty: true
+          destination: false
+          entity_type: registrant
+          plugin_id: entity_operations
+      menu:
+        type: none
+        title: ''
+        description: ''
+        expanded: false
+        parent: ''
+        weight: 0
+        context: '0'
+        menu_name: main
+      sorts:
+        created:
+          id: created
+          table: registrant
+          field: created
+          relationship: none
+          group_type: group
+          admin_label: ''
+          order: ASC
+          exposed: false
+          expose:
+            label: ''
+          granularity: second
+          entity_type: registrant
+          entity_field: created
+          plugin_id: date
+      access:
+        type: event_registration_list_access
+        options: {  }
+    cache_metadata:
+      max-age: -1
+      contexts:
+        - 'languages:language_content'
+        - 'languages:language_interface'
+        - url
+        - url.query_args
+      tags: {  }
+  user_event_registrations:
+    display_plugin: page
+    id: user_event_registrations
+    display_title: Page
+    position: 3
+    display_options:
+      display_extenders: {  }
+      path: user/%user/registrations
+      arguments:
+        user_id:
+          id: user_id
+          table: registrant
+          field: user_id
+          relationship: none
+          group_type: group
+          admin_label: ''
+          default_action: default
+          exception:
+            value: all
+            title_enable: false
+            title: All
+          title_enable: false
+          title: ''
+          default_argument_type: user
+          default_argument_options:
+            user: false
+          default_argument_skip_url: false
+          summary_options:
+            base_path: ''
+            count: true
+            items_per_page: 25
+            override: false
+          summary:
+            sort_order: asc
+            number_of_records: 0
+            format: default_summary
+          specify_validation: false
+          validate:
+            type: none
+            fail: 'not found'
+          validate_options: {  }
+          break_phrase: false
+          not: false
+          entity_type: registrant
+          entity_field: user_id
+          plugin_id: numeric
+      defaults:
+        arguments: false
+        filters: false
+        filter_groups: false
+        fields: false
+        sorts: false
+      filters:
+        title:
+          id: title
+          table: eventseries_field_data
+          field: title
+          relationship: eventseries_id
+          group_type: group
+          admin_label: ''
+          operator: contains
+          value: ''
+          group: 1
+          exposed: true
+          expose:
+            operator_id: title_op
+            label: 'Event Name'
+            description: ''
+            use_operator: false
+            operator: title_op
+            identifier: title
+            required: false
+            remember: false
+            multiple: false
+            remember_roles:
+              authenticated: authenticated
+              anonymous: '0'
+              administrator: '0'
+            placeholder: ''
+            operator_limit_selection: false
+            operator_list: {  }
+          is_grouped: false
+          group_info:
+            label: ''
+            description: ''
+            identifier: ''
+            optional: true
+            widget: select
+            multiple: false
+            remember: false
+            default_group: All
+            default_group_multiple: {  }
+            group_items: {  }
+          entity_type: eventseries
+          entity_field: title
+          plugin_id: string
+        waitlist:
+          id: waitlist
+          table: registrant
+          field: waitlist
+          relationship: none
+          group_type: group
+          admin_label: ''
+          operator: '='
+          value: All
+          group: 1
+          exposed: true
+          expose:
+            operator_id: ''
+            label: Waitlist
+            description: ''
+            use_operator: false
+            operator: waitlist_op
+            identifier: waitlist
+            required: false
+            remember: false
+            multiple: false
+            remember_roles:
+              authenticated: authenticated
+              anonymous: '0'
+              administrator: '0'
+            operator_limit_selection: false
+            operator_list: {  }
+          is_grouped: false
+          group_info:
+            label: ''
+            description: ''
+            identifier: ''
+            optional: true
+            widget: select
+            multiple: false
+            remember: false
+            default_group: All
+            default_group_multiple: {  }
+            group_items: {  }
+          entity_type: registrant
+          entity_field: waitlist
+          plugin_id: boolean
+        type:
+          id: type
+          table: registrant
+          field: type
+          relationship: none
+          group_type: group
+          admin_label: ''
+          operator: contains
+          value: ''
+          group: 1
+          exposed: true
+          expose:
+            operator_id: type_op
+            label: Type
+            description: ''
+            use_operator: false
+            operator: type_op
+            identifier: type
+            required: false
+            remember: false
+            multiple: false
+            remember_roles:
+              authenticated: authenticated
+              anonymous: '0'
+              administrator: '0'
+            placeholder: ''
+            operator_limit_selection: false
+            operator_list: {  }
+          is_grouped: false
+          group_info:
+            label: ''
+            description: ''
+            identifier: ''
+            optional: true
+            widget: select
+            multiple: false
+            remember: false
+            default_group: All
+            default_group_multiple: {  }
+            group_items: {  }
+          entity_type: registrant
+          entity_field: type
+          plugin_id: string
+        created_1:
+          id: created_1
+          table: registrant
+          field: created
+          relationship: none
+          group_type: group
+          admin_label: ''
+          operator: '<='
+          value:
+            min: ''
+            max: ''
+            value: ''
+            type: date
+          group: 1
+          exposed: true
+          expose:
+            operator_id: created_1_op
+            label: 'Created Before'
+            description: ''
+            use_operator: false
+            operator: created_1_op
+            identifier: created_1
+            required: false
+            remember: false
+            multiple: false
+            remember_roles:
+              authenticated: authenticated
+              anonymous: '0'
+              administrator: '0'
+            placeholder: ''
+            min_placeholder: ''
+            max_placeholder: ''
+            operator_limit_selection: false
+            operator_list: {  }
+          is_grouped: false
+          group_info:
+            label: ''
+            description: ''
+            identifier: ''
+            optional: true
+            widget: select
+            multiple: false
+            remember: false
+            default_group: All
+            default_group_multiple: {  }
+            group_items: {  }
+          entity_type: registrant
+          entity_field: created
+          plugin_id: date
+        created_2:
+          id: created_2
+          table: registrant
+          field: created
+          relationship: none
+          group_type: group
+          admin_label: ''
+          operator: '>='
+          value:
+            min: ''
+            max: ''
+            value: ''
+            type: date
+          group: 1
+          exposed: true
+          expose:
+            operator_id: created_2_op
+            label: 'Created After'
+            description: ''
+            use_operator: false
+            operator: created_2_op
+            identifier: created_2
+            required: false
+            remember: false
+            multiple: false
+            remember_roles:
+              authenticated: authenticated
+              anonymous: '0'
+              administrator: '0'
+            placeholder: ''
+            min_placeholder: ''
+            max_placeholder: ''
+            operator_limit_selection: false
+            operator_list: {  }
+          is_grouped: false
+          group_info:
+            label: ''
+            description: ''
+            identifier: ''
+            optional: true
+            widget: select
+            multiple: false
+            remember: false
+            default_group: All
+            default_group_multiple: {  }
+            group_items: {  }
+          entity_type: registrant
+          entity_field: created
+          plugin_id: date
+      filter_groups:
+        operator: AND
+        groups:
+          1: AND
+      fields:
+        title:
+          id: title
+          table: eventseries_field_data
+          field: title
+          relationship: eventseries_id
+          group_type: group
+          admin_label: ''
+          label: ''
+          exclude: true
+          alter:
+            alter_text: false
+            text: ''
+            make_link: false
+            path: ''
+            absolute: false
+            external: false
+            replace_spaces: false
+            path_case: none
+            trim_whitespace: false
+            alt: ''
+            rel: ''
+            link_class: ''
+            prefix: ''
+            suffix: ''
+            target: ''
+            nl2br: false
+            max_length: 0
+            word_boundary: true
+            ellipsis: true
+            more_link: false
+            more_link_text: ''
+            more_link_path: ''
+            strip_tags: false
+            trim: false
+            preserve_tags: ''
+            html: false
+          element_type: ''
+          element_class: ''
+          element_label_type: ''
+          element_label_class: ''
+          element_label_colon: false
+          element_wrapper_type: ''
+          element_wrapper_class: ''
+          element_default_classes: true
+          empty: ''
+          hide_empty: false
+          empty_zero: false
+          hide_alter_empty: true
+          click_sort_column: value
+          type: string
+          settings:
+            link_to_entity: false
+          group_column: value
+          group_columns: {  }
+          group_rows: true
+          delta_limit: 0
+          delta_offset: 0
+          delta_reversed: false
+          delta_first_last: false
+          multi_type: separator
+          separator: ', '
+          field_api_classes: false
+          entity_type: eventseries
+          entity_field: title
+          plugin_id: field
+        view_eventinstance:
+          id: view_eventinstance
+          table: eventinstance
+          field: view_eventinstance
+          relationship: eventinstance_id
+          group_type: group
+          admin_label: ''
+          label: ''
+          exclude: true
+          alter:
+            alter_text: false
+            text: ''
+            make_link: false
+            path: ''
+            absolute: false
+            external: false
+            replace_spaces: false
+            path_case: none
+            trim_whitespace: false
+            alt: ''
+            rel: ''
+            link_class: ''
+            prefix: ''
+            suffix: ''
+            target: ''
+            nl2br: false
+            max_length: 0
+            word_boundary: true
+            ellipsis: true
+            more_link: false
+            more_link_text: ''
+            more_link_path: ''
+            strip_tags: false
+            trim: false
+            preserve_tags: ''
+            html: false
+          element_type: ''
+          element_class: ''
+          element_label_type: ''
+          element_label_class: ''
+          element_label_colon: false
+          element_wrapper_type: ''
+          element_wrapper_class: ''
+          element_default_classes: true
+          empty: ''
+          hide_empty: false
+          empty_zero: false
+          hide_alter_empty: true
+          text: view
+          output_url_as_text: true
+          absolute: false
+          entity_type: eventinstance
+          plugin_id: entity_link
+        view_eventseries:
+          id: view_eventseries
+          table: eventseries
+          field: view_eventseries
+          relationship: eventseries_id
+          group_type: group
+          admin_label: ''
+          label: ''
+          exclude: true
+          alter:
+            alter_text: false
+            text: ''
+            make_link: false
+            path: ''
+            absolute: false
+            external: false
+            replace_spaces: false
+            path_case: none
+            trim_whitespace: false
+            alt: ''
+            rel: ''
+            link_class: ''
+            prefix: ''
+            suffix: ''
+            target: ''
+            nl2br: false
+            max_length: 0
+            word_boundary: true
+            ellipsis: true
+            more_link: false
+            more_link_text: ''
+            more_link_path: ''
+            strip_tags: false
+            trim: false
+            preserve_tags: ''
+            html: false
+          element_type: ''
+          element_class: ''
+          element_label_type: ''
+          element_label_class: ''
+          element_label_colon: false
+          element_wrapper_type: ''
+          element_wrapper_class: ''
+          element_default_classes: true
+          empty: ''
+          hide_empty: false
+          empty_zero: false
+          hide_alter_empty: true
+          text: view
+          output_url_as_text: true
+          absolute: false
+          entity_type: eventseries
+          plugin_id: entity_link
+        id:
+          id: id
+          table: registrant
+          field: id
+          relationship: none
+          group_type: group
+          admin_label: ''
+          label: ID
+          exclude: false
+          alter:
+            alter_text: false
+            text: ''
+            make_link: false
+            path: ''
+            absolute: false
+            external: false
+            replace_spaces: false
+            path_case: none
+            trim_whitespace: false
+            alt: ''
+            rel: ''
+            link_class: ''
+            prefix: ''
+            suffix: ''
+            target: ''
+            nl2br: false
+            max_length: 0
+            word_boundary: true
+            ellipsis: true
+            more_link: false
+            more_link_text: ''
+            more_link_path: ''
+            strip_tags: false
+            trim: false
+            preserve_tags: ''
+            html: false
+          element_type: ''
+          element_class: ''
+          element_label_type: ''
+          element_label_class: ''
+          element_label_colon: true
+          element_wrapper_type: ''
+          element_wrapper_class: ''
+          element_default_classes: true
+          empty: ''
+          hide_empty: false
+          empty_zero: false
+          hide_alter_empty: true
+          click_sort_column: value
+          type: number_integer
+          settings:
+            thousand_separator: ''
+            prefix_suffix: true
+          group_column: value
+          group_columns: {  }
+          group_rows: true
+          delta_limit: 0
+          delta_offset: 0
+          delta_reversed: false
+          delta_first_last: false
+          multi_type: separator
+          separator: ', '
+          field_api_classes: false
+          entity_type: registrant
+          entity_field: id
+          plugin_id: field
+        title_1:
+          id: title_1
+          table: eventseries_field_data
+          field: title
+          relationship: eventseries_id
+          group_type: group
+          admin_label: ''
+          label: 'Event Series'
+          exclude: false
+          alter:
+            alter_text: true
+            text: '{{ title }}'
+            make_link: true
+            path: '{{ view_eventseries }}'
+            absolute: false
+            external: false
+            replace_spaces: false
+            path_case: none
+            trim_whitespace: false
+            alt: ''
+            rel: ''
+            link_class: ''
+            prefix: ''
+            suffix: ''
+            target: ''
+            nl2br: false
+            max_length: 0
+            word_boundary: true
+            ellipsis: true
+            more_link: false
+            more_link_text: ''
+            more_link_path: ''
+            strip_tags: false
+            trim: false
+            preserve_tags: ''
+            html: false
+          element_type: ''
+          element_class: ''
+          element_label_type: ''
+          element_label_class: ''
+          element_label_colon: true
+          element_wrapper_type: ''
+          element_wrapper_class: ''
+          element_default_classes: true
+          empty: ''
+          hide_empty: false
+          empty_zero: false
+          hide_alter_empty: true
+          click_sort_column: value
+          type: string
+          settings:
+            link_to_entity: false
+          group_column: value
+          group_columns: {  }
+          group_rows: true
+          delta_limit: 0
+          delta_offset: 0
+          delta_reversed: false
+          delta_first_last: false
+          multi_type: separator
+          separator: ', '
+          field_api_classes: false
+          entity_type: eventseries
+          entity_field: title
+          plugin_id: field
+        date__value:
+          id: date__value
+          table: eventinstance_field_data
+          field: date__value
+          relationship: eventinstance_id
+          group_type: group
+          admin_label: ''
+          label: 'Event Date'
+          exclude: false
+          alter:
+            alter_text: true
+            text: '{{ date__value }}'
+            make_link: true
+            path: '{{ view_eventinstance }}'
+            absolute: false
+            external: false
+            replace_spaces: false
+            path_case: none
+            trim_whitespace: false
+            alt: ''
+            rel: ''
+            link_class: ''
+            prefix: ''
+            suffix: ''
+            target: ''
+            nl2br: false
+            max_length: 0
+            word_boundary: true
+            ellipsis: true
+            more_link: false
+            more_link_text: ''
+            more_link_path: ''
+            strip_tags: false
+            trim: false
+            preserve_tags: ''
+            html: false
+          element_type: ''
+          element_class: ''
+          element_label_type: ''
+          element_label_class: ''
+          element_label_colon: true
+          element_wrapper_type: ''
+          element_wrapper_class: ''
+          element_default_classes: true
+          empty: ''
+          hide_empty: false
+          empty_zero: false
+          hide_alter_empty: true
+          click_sort_column: value
+          type: daterange_default
+          settings:
+            timezone_override: ''
+            format_type: medium
+            fromto: start_date
+            separator: '-'
+          group_column: value
+          group_columns: {  }
+          group_rows: true
+          delta_limit: 0
+          delta_offset: 0
+          delta_reversed: false
+          delta_first_last: false
+          multi_type: separator
+          separator: ', '
+          field_api_classes: false
+          entity_type: eventinstance
+          entity_field: date
+          plugin_id: field
+        waitlist:
+          id: waitlist
+          table: registrant
+          field: waitlist
+          relationship: none
+          group_type: group
+          admin_label: ''
+          label: Waitlist
+          exclude: false
+          alter:
+            alter_text: false
+            text: ''
+            make_link: false
+            path: ''
+            absolute: false
+            external: false
+            replace_spaces: false
+            path_case: none
+            trim_whitespace: false
+            alt: ''
+            rel: ''
+            link_class: ''
+            prefix: ''
+            suffix: ''
+            target: ''
+            nl2br: false
+            max_length: 0
+            word_boundary: true
+            ellipsis: true
+            more_link: false
+            more_link_text: ''
+            more_link_path: ''
+            strip_tags: false
+            trim: false
+            preserve_tags: ''
+            html: false
+          element_type: ''
+          element_class: ''
+          element_label_type: ''
+          element_label_class: ''
+          element_label_colon: true
+          element_wrapper_type: ''
+          element_wrapper_class: ''
+          element_default_classes: true
+          empty: ''
+          hide_empty: false
+          empty_zero: false
+          hide_alter_empty: true
+          click_sort_column: value
+          type: boolean
+          settings:
+            format: yes-no
+            format_custom_true: ''
+            format_custom_false: ''
+          group_column: value
+          group_columns: {  }
+          group_rows: true
+          delta_limit: 0
+          delta_offset: 0
+          delta_reversed: false
+          delta_first_last: false
+          multi_type: separator
+          separator: ', '
+          field_api_classes: false
+          entity_type: registrant
+          entity_field: waitlist
+          plugin_id: field
+        type:
+          id: type
+          table: registrant
+          field: type
+          relationship: none
+          group_type: group
+          admin_label: ''
+          label: Type
+          exclude: false
+          alter:
+            alter_text: false
+            text: ''
+            make_link: false
+            path: ''
+            absolute: false
+            external: false
+            replace_spaces: false
+            path_case: none
+            trim_whitespace: false
+            alt: ''
+            rel: ''
+            link_class: ''
+            prefix: ''
+            suffix: ''
+            target: ''
+            nl2br: false
+            max_length: 0
+            word_boundary: true
+            ellipsis: true
+            more_link: false
+            more_link_text: ''
+            more_link_path: ''
+            strip_tags: false
+            trim: false
+            preserve_tags: ''
+            html: false
+          element_type: ''
+          element_class: ''
+          element_label_type: ''
+          element_label_class: ''
+          element_label_colon: true
+          element_wrapper_type: ''
+          element_wrapper_class: ''
+          element_default_classes: true
+          empty: ''
+          hide_empty: false
+          empty_zero: false
+          hide_alter_empty: true
+          click_sort_column: value
+          type: string
+          settings:
+            link_to_entity: false
+          group_column: value
+          group_columns: {  }
+          group_rows: true
+          delta_limit: 0
+          delta_offset: 0
+          delta_reversed: false
+          delta_first_last: false
+          multi_type: separator
+          separator: ', '
+          field_api_classes: false
+          entity_type: registrant
+          entity_field: type
+          plugin_id: field
+        operations:
+          id: operations
+          table: registrant
+          field: operations
+          relationship: none
+          group_type: group
+          admin_label: ''
+          label: Operations
+          exclude: false
+          alter:
+            alter_text: false
+            text: ''
+            make_link: false
+            path: ''
+            absolute: false
+            external: false
+            replace_spaces: false
+            path_case: none
+            trim_whitespace: false
+            alt: ''
+            rel: ''
+            link_class: ''
+            prefix: ''
+            suffix: ''
+            target: ''
+            nl2br: false
+            max_length: 0
+            word_boundary: true
+            ellipsis: true
+            more_link: false
+            more_link_text: ''
+            more_link_path: ''
+            strip_tags: false
+            trim: false
+            preserve_tags: ''
+            html: false
+          element_type: ''
+          element_class: ''
+          element_label_type: ''
+          element_label_class: ''
+          element_label_colon: true
+          element_wrapper_type: ''
+          element_wrapper_class: ''
+          element_default_classes: true
+          empty: ''
+          hide_empty: false
+          empty_zero: false
+          hide_alter_empty: true
+          destination: false
+          entity_type: registrant
+          plugin_id: entity_operations
+      sorts:
+        date__value:
+          id: date__value
+          table: eventinstance_field_data
+          field: date__value
+          relationship: eventinstance_id
+          group_type: group
+          admin_label: ''
+          order: ASC
+          exposed: false
+          expose:
+            label: ''
+          granularity: second
+          entity_type: eventinstance
+          entity_field: date
+          plugin_id: datetime
+      menu:
+        type: tab
+        title: Registrations
+        description: ''
+        expanded: false
+        parent: ''
+        weight: 0
+        context: '0'
+        menu_name: account
+    cache_metadata:
+      max-age: -1
+      contexts:
+        - 'languages:language_content'
+        - 'languages:language_interface'
+        - url
+        - url.query_args
+        - user.permissions
+      tags: {  }
diff --git a/modules/recurring_events_views/recurring_events_views.info.yml b/modules/recurring_events_views/recurring_events_views.info.yml
new file mode 100644
index 0000000000000000000000000000000000000000..19105633810bda52ab85af665b0e8d1e5385135d
--- /dev/null
+++ b/modules/recurring_events_views/recurring_events_views.info.yml
@@ -0,0 +1,9 @@
+name: 'Recurring Events Views'
+type: module
+description: 'Swaps all recurring events list builders for views'
+core: 8.x
+package: 'Recurring Events'
+core_version_requirement: ^8 || ^9
+dependencies:
+  - drupal:views
+  - recurring_events:recurring_events
diff --git a/modules/recurring_events_views/recurring_events_views.install b/modules/recurring_events_views/recurring_events_views.install
new file mode 100644
index 0000000000000000000000000000000000000000..706035c6a00b91174f39d290dd747ddbe8464d28
--- /dev/null
+++ b/modules/recurring_events_views/recurring_events_views.install
@@ -0,0 +1,28 @@
+<?php
+
+/**
+ * @file
+ * Install and update functionalit for the recurring_events_views module.
+ */
+
+use Drupal\views\Views;
+
+/**
+ * Install the menu tab view display option for the user registration view.
+ */
+function recurring_events_views_update_8001() {
+  $view = Views::getView('registrations');
+  $display = &$view->storage->getDisplay('user_event_registrations');
+  $display['display_options']['menu'] = [
+    'type' => 'tab',
+    'title' => 'Registrations',
+    'description' => '',
+    'expanded' => FALSE,
+    'parent' => '',
+    'weight' => 0,
+    'context' => '0',
+    'menu_name' => 'account',
+  ];
+  $view->storage->save();
+  $view->storage->invalidateCaches();
+}
diff --git a/modules/recurring_events_views/recurring_events_views.module b/modules/recurring_events_views/recurring_events_views.module
new file mode 100644
index 0000000000000000000000000000000000000000..0624dc42c3b35130984275873d1aaced6f1b70fb
--- /dev/null
+++ b/modules/recurring_events_views/recurring_events_views.module
@@ -0,0 +1,151 @@
+<?php
+
+/**
+ * @file
+ * Contains recurring_events_views.module.
+ */
+
+use Drupal\Core\Routing\RouteMatchInterface;
+use Drupal\views\ViewExecutable;
+use Drupal\views\Plugin\views\query\QueryPluginBase;
+use Drupal\Component\Utility\Html;
+use Symfony\Component\Routing\Exception\RouteNotFoundException;
+
+/**
+ * Implements hook_help().
+ */
+function recurring_events_views_help($route_name, RouteMatchInterface $route_match) {
+  switch ($route_name) {
+    // Main module help for the recurring_events_views module.
+    case 'help.page.recurring_events_views':
+      $text = file_get_contents(__DIR__ . '/README.md');
+      if (!\Drupal::moduleHandler()->moduleExists('markdown')) {
+        return '<pre>' . Html::escape($text) . '</pre>';
+      }
+      else {
+        // Use the Markdown filter to render the README.
+        $filter_manager = \Drupal::service('plugin.manager.filter');
+        $settings = \Drupal::configFactory()->get('markdown.settings')->getRawData();
+        $config = ['settings' => $settings];
+        $filter = $filter_manager->createInstance('markdown', $config);
+        return $filter->process($text, 'en');
+      }
+      break;
+  }
+}
+
+/**
+ * Implements hook_local_tasks_alter().
+ */
+function recurring_events_views_local_tasks_alter(&$local_tasks) {
+  if (\Drupal::moduleHandler()->moduleExists('recurring_events_registration')) {
+    try {
+      if (\Drupal::service('router.route_provider')->getRouteByName('view.registrations.event_registrant_list')) {
+        if (!empty($local_tasks['entity.registrant.instance_listing'])) {
+          $local_tasks['entity.registrant.instance_listing']['route_name'] = 'view.registrations.event_registrant_list';
+          $local_tasks['entity.registrant.instance_listing']['id'] = 'view.registrations.event_registrant_list';
+        }
+      }
+    }
+    catch (RouteNotFoundException $exception) {
+      \Drupal::logger('recurring_events_views')->error($exception->getMessage());
+    }
+
+    if (!empty($local_tasks['views_view:view.registrations.user_event_registrations'])) {
+      unset($local_tasks['entity.user.registrations']);
+    }
+  }
+}
+
+/**
+ * Implements hook_views_query_alter().
+ */
+function recurring_events_views_views_query_alter(ViewExecutable $view, QueryPluginBase $query) {
+  // Because registration is complicated by series vs instance registration we
+  // need to modify the view to accomodate that. If an event has series
+  // registration then viewing the registration list on any of the instances
+  // should display all registrations for that event. However, if the event has
+  // instance registration, then we should only see registrations for the
+  // particular instance being viewed.
+  if ($view->id() === 'registrations' && $view->current_display === 'event_registrant_list') {
+    if (\Drupal::moduleHandler()->moduleExists('recurring_events_registration')) {
+      $eventinstance_id = \Drupal::routeMatch()->getParameters()->get('eventinstance');
+
+      if (!empty($eventinstance_id)) {
+        $eventinstance = \Drupal::entityTypeManager()->getStorage('eventinstance')->load($eventinstance_id);
+        if (!empty($eventinstance)) {
+          $service = \Drupal::service('recurring_events_registration.creation_service');
+          $service->setEventInstance($eventinstance);
+          switch ($service->getRegistrationType()) {
+            case 'instance':
+              $field = 'registrant.eventinstance_id';
+              $value = [
+                $eventinstance->id(),
+              ];
+              break;
+
+            case 'series':
+            default:
+              $field = 'registrant.eventseries_id';
+              $value = [
+                $eventinstance->getEventSeries()->id(),
+              ];
+              break;
+          }
+        }
+
+        if (!empty($field) && !empty($value)) {
+          $query->where[1]['conditions'][] = [
+            'field' => $field,
+            'value' => $value,
+            'operator' => '=',
+          ];
+        }
+      }
+    }
+  }
+}
+
+/**
+ * Implements hook_views_pre_render().
+ */
+function recurring_events_views_views_pre_render(ViewExecutable $view) {
+  // Because registration is complicated by series vs instance registration we
+  // need to modify the view title to accomodate that.
+  if ($view->id() === 'registrations' && $view->current_display === 'event_registrant_list') {
+    if (\Drupal::moduleHandler()->moduleExists('recurring_events_registration')) {
+      $eventinstance_id = \Drupal::routeMatch()->getParameters()->get('eventinstance');
+
+      if (!empty($eventinstance_id)) {
+        $eventinstance = \Drupal::entityTypeManager()->getStorage('eventinstance')->load($eventinstance_id);
+        $service = \Drupal::service('recurring_events_registration.creation_service');
+        if (!empty($eventinstance)) {
+          $service->setEventInstance($eventinstance);
+          $config = \Drupal::config('recurring_events.eventinstance.config');
+          $format = $config->get('date_format');
+          $name = $eventinstance->title->value;
+          switch ($service->getRegistrationType()) {
+            case 'instance':
+              $title = t('Registrations for %name on %date', [
+                '%name' => $name,
+                '%date' => $eventinstance->date->start_date->format($format),
+              ]);
+              break;
+
+            case 'series':
+            default:
+              $title = t('Registrations for series: %name', [
+                '%name' => $name,
+              ]);
+              break;
+          }
+
+          if (!empty($title)) {
+            $view->setTitle($title);
+          }
+        }
+      }
+    }
+
+  }
+}
diff --git a/phpunit.xml b/phpunit.xml
new file mode 100644
index 0000000000000000000000000000000000000000..08d699d118f1c53371827f6ad6772c2802b5b0a8
--- /dev/null
+++ b/phpunit.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<phpunit colors="true">
+    <php>
+        <!-- Set error reporting to E_ALL. -->
+        <ini name="error_reporting" value="32767"/>
+        <!-- Do not limit the amount of memory tests take to run. -->
+        <ini name="memory_limit" value="-1"/>
+    </php>
+    <testsuites>
+        <testsuite name="Recurring Events Test Suite">
+            <directory>./tests</directory>
+            <!-- directory>./modules/recurring_events_registration/tests</directory -->
+            <!-- directory>./modules/recurring_events_views/tests</directory -->
+        </testsuite>
+    </testsuites>
+</phpunit>
diff --git a/recurring_events.api.php b/recurring_events.api.php
index 798bf2a1608e05241ec96ac51d81f0c16535b6a1..fdfadb85cb5211d621c3c5b446ded79d737595b4 100644
--- a/recurring_events.api.php
+++ b/recurring_events.api.php
@@ -90,7 +90,7 @@ function hook_recurring_events_form_config_array_alter(array &$form_config = [])
  */
 function hook_recurring_events_entity_config_array_alter(array &$entity_config = []) {
   // Remove the first custom date.
-  unset($form_config['custom_dates'][0]);
+  unset($entity_config['custom_dates'][0]);
 }
 
 /**
@@ -101,21 +101,7 @@ function hook_recurring_events_entity_config_array_alter(array &$entity_config =
  */
 function hook_recurring_events_diff_array_alter(array &$diff = []) {
   // Do not show differences in custom dates.
-  unset($form_config['custom_dates']);
-}
-
-/**
- * Alter the inheritance class used to build the inherited basefield.
- *
- * @var string $class
- *   The class to alter.
- * @var Drupal\Core\Field\FieldDefinitionInterface $field
- *   The field context.
- */
-function hook_recurring_events_inheritance_class_alter(&$class, $field) {
-  if ($field->plugin() === 'entity_reference_inheritance') {
-    $class = '\Drupal\my_module\EntityReferenceFieldInheritanceFactory';
-  }
+  unset($diff['custom_dates']);
 }
 
 /**
diff --git a/recurring_events.info.yml b/recurring_events.info.yml
index 071ecf065df854b622837d18fe025e354a13c49a..9b534c83e430b2b90e4bdf3741f8fd2bb462baef 100644
--- a/recurring_events.info.yml
+++ b/recurring_events.info.yml
@@ -6,4 +6,5 @@ core_version_requirement: ^8 || ^9
 package: 'Recurring Events'
 dependencies:
   - drupal:datetime_range
-  - drupal:options
\ No newline at end of file
+  - drupal:options
+  - field_inheritance:field_inheritance
diff --git a/recurring_events.install b/recurring_events.install
index cf479472ff87ad71fb49f229ecdb9c87c4b51310..131f4207839015b0d0600d32834da351cf99b81d 100644
--- a/recurring_events.install
+++ b/recurring_events.install
@@ -5,8 +5,10 @@
  * Installation and update functionality for the recurring_events module.
  */
 
+use Drupal\Core\Config\Entity\ConfigEntityType;
 use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Field\BaseFieldDefinition;
+use Drupal\Core\Config\FileStorage;
 
 /**
  * Install the excluded and included date fields.
@@ -28,7 +30,6 @@ function recurring_events_update_8001() {
     ->setSetting('datetime_type', 'date')
     ->setDisplayOptions('form', [
       'type' => 'daterange_default',
-      'label' => 'above',
       'weight' => 6,
       'settings' => [
         'format_type' => 'html_date',
@@ -50,7 +51,6 @@ function recurring_events_update_8001() {
     ->setSetting('datetime_type', 'date')
     ->setDisplayOptions('form', [
       'type' => 'daterange_default',
-      'label' => 'above',
       'weight' => 6,
       'settings' => [
         'format_type' => 'html_date',
@@ -169,3 +169,260 @@ function recurring_events_update_8004() {
   $config->set('threshold_prevent_save', 0);
   $config->save(TRUE);
 }
+
+/**
+ * Install the new config entities for event series and instance bundles.
+ */
+function recurring_events_update_8005() {
+  /*
+   * @see https://www.drupal.org/node/3069090
+   */
+  \Drupal::entityDefinitionUpdateManager()->installEntityType(new ConfigEntityType([
+    'id' => 'eventseries_type',
+    'label' => new TranslatableMarkup('Event series type'),
+    'handlers' => [
+      'view_builder' => 'Drupal\Core\Entity\EntityViewBuilder',
+      'list_builder' => 'Drupal\recurring_events\EventSeriesTypeListBuilder',
+      'form' => [
+        'add' => 'Drupal\recurring_events\Form\EventSeriesTypeForm',
+        'edit' => 'Drupal\recurring_events\Form\EventSeriesTypeForm',
+        'delete' => 'Drupal\recurring_events\Form\EventSeriesTypeDeleteForm',
+      ],
+      'route_provider' => [
+        'html' => 'Drupal\recurring_events\EventSeriesTypeHtmlRouteProvider',
+      ],
+    ],
+    'config_prefix' => 'eventseries_type',
+    'bundle_of' => 'eventseries',
+    'admin_permission' => 'administer eventseries entity',
+    'entity_keys' => [
+      'id' => 'id',
+      'label' => 'label',
+      'uuid' => 'uuid',
+    ],
+    'links' => [
+      'canonical' => '/admin/structure/events/series/types/eventseries_type/{eventseries_type}',
+      'add-form' => '/admin/structure/events/series/types/eventseries_type/add',
+      'edit-form' => '/admin/structure/events/series/types/eventseries_type/{eventseries_type}/edit',
+      'delete-form' => '/admin/structure/events/series/types/eventseries_type/{eventseries_type}/delete',
+      'collection' => '/admin/structure/events/series/types/eventseries_type',
+    ],
+    'config_export' => [
+      'label',
+      'id',
+      'description',
+    ],
+  ]));
+
+  \Drupal::entityDefinitionUpdateManager()->installEntityType(new ConfigEntityType([
+    'id' => 'eventinstance_type',
+    'label' => new TranslatableMarkup('Event instance type'),
+    'handlers' => [
+      'view_builder' => 'Drupal\Core\Entity\EntityViewBuilder',
+      'list_builder' => 'Drupal\recurring_events\EventSeriesTypeListBuilder',
+      'form' => [
+        'add' => 'Drupal\recurring_events\Form\EventSeriesTypeForm',
+        'edit' => 'Drupal\recurring_events\Form\EventSeriesTypeForm',
+        'delete' => 'Drupal\recurring_events\Form\EventSeriesTypeDeleteForm',
+      ],
+      'route_provider' => [
+        'html' => 'Drupal\recurring_events\EventSeriesTypeHtmlRouteProvider',
+      ],
+    ],
+    'config_prefix' => 'eventinstance_type',
+    'bundle_of' => 'eventinstance',
+    'admin_permission' => 'administer eventinstance entity',
+    'entity_keys' => [
+      'id' => 'id',
+      'label' => 'label',
+      'uuid' => 'uuid',
+    ],
+    'links' => [
+      'canonical' => '/admin/structure/events/instance/types/eventinstance_type/{eventinstance_type}',
+      'add-form' => '/admin/structure/events/instance/types/eventinstance_type/add',
+      'edit-form' => '/admin/structure/events/instance/types/eventinstance_type/{eventinstance_type}/edit',
+      'delete-form' => '/admin/structure/events/instance/types/eventinstance_type/{eventinstance_type}/delete',
+      'collection' => '/admin/structure/events/instance/types/eventinstance_type',
+    ],
+    'config_export' => [
+      'label',
+      'id',
+      'description',
+    ],
+  ]));
+}
+
+/**
+ * Install the new type basefields for series and instances.
+ */
+function recurring_events_update_8006() {
+  $series_type = BaseFieldDefinition::create('entity_reference')
+    ->setLabel(t('Type'))
+    ->setDescription(t('The eventseries type.'))
+    ->setSetting('target_type', 'eventseries_type')
+    ->setReadOnly(TRUE);
+
+  \Drupal::entityDefinitionUpdateManager()->installFieldStorageDefinition('type', 'eventseries', 'eventseries', $series_type);
+
+  $instance_type = BaseFieldDefinition::create('entity_reference')
+    ->setLabel(t('Type'))
+    ->setDescription(t('The eventinstance type.'))
+    ->setSetting('target_type', 'eventinstance_type')
+    ->setReadOnly(TRUE);
+
+  \Drupal::entityDefinitionUpdateManager()->installFieldStorageDefinition('type', 'eventinstance', 'eventinstance', $instance_type);
+}
+
+/**
+ * Transition existing field inheritance entities over to new module.
+ */
+function recurring_events_update_8007() {
+  \Drupal::service('module_installer')->install(['field_inheritance']);
+  $database = \Drupal::database();
+  $inherited_fields = $database->select('config', 'c')
+    ->fields('c', ['name'])
+    ->condition('name', 'recurring_events.field_inheritance.%', 'LIKE')
+    ->execute()
+    ->fetchCol();
+  $bundles = \Drupal::service('entity_type.bundle.info')->getBundleInfo('eventseries');
+
+  if (!empty($inherited_fields)) {
+    foreach ($inherited_fields as $inherited_field) {
+      $field = \Drupal::configFactory()->getEditable($inherited_field);
+      foreach ($bundles as $bundle_key => $bundle) {
+        $data = $field->getRawData();
+        $id_parts = [
+          'eventinstance',
+          $bundle_key,
+          $data['id'],
+        ];
+        $name = 'field_inheritance.field_inheritance.' . implode('_', $id_parts);
+
+        $data['id'] = implode('_', $id_parts);
+        $data['sourceEntityType'] = 'eventseries';
+        $data['sourceEntityBundle'] = $bundle_key;
+        $data['destinationEntityType'] = 'eventinstance';
+        $data['destinationEntityBundle'] = $bundle_key;
+        $data['plugin'] = 'default_inheritance';
+
+        if (!empty($data['entityField'])) {
+          $data['destinationField'] = $data['entityField'];
+          unset($data['entityField']);
+        }
+        $field->setName($name)->setData($data)->save();
+      }
+    }
+    $database->delete('config')
+      ->condition('name', 'recurring_events.field_inheritance.%', 'LIKE')
+      ->execute();
+  }
+
+  drupal_flush_all_caches();
+}
+
+/**
+ * Enable the eventinstance bundles to allow inheritance.
+ */
+function recurring_events_update_8008() {
+  // Enable the eventinstance bundles to allow inheritance.
+  $config = \Drupal::configFactory()->getEditable('field_inheritance.config');
+  $bundles = \Drupal::service('entity_type.bundle.info')->getBundleInfo('eventseries');
+  $data = $config->getRawData();
+
+  $included_entities = $data['included_entities'];
+  $included_entities = explode(',', $included_entities);
+  $included_entities[] = 'eventinstance';
+  sort($included_entities);
+  $data['included_entities'] = implode(',', $included_entities);
+
+  $included_bundles = $data['included_bundles'];
+  $included_bundles = explode(',', $included_bundles);
+  foreach ($bundles as $bundle_key => $bundle) {
+    $included_bundles[] = 'eventinstance:' . $bundle_key;
+  }
+  sort($included_bundles);
+  $data['included_bundles'] = implode(',', $included_bundles);
+  $config->setData($data)->save();
+
+  drupal_flush_all_caches();
+}
+
+/**
+ * Update all existing event instances.
+ */
+function recurring_events_update_8009(&$sandbox) {
+  // This is a multipass update.
+  if (empty($sandbox['events'])) {
+    $events = \Drupal::entityQuery('eventinstance')->execute();
+    $sandbox['events'] = $events;
+    $sandbox['max'] = count($events);
+    $sandbox['limit'] = 50;
+    $sandbox['progress'] = 0;
+  }
+
+  if (count($sandbox['events']) > 0) {
+    // Loop through chunks of 20 events at a time.
+    $events = array_splice($sandbox['events'], 0, $sandbox['limit'], []);
+    if (!empty($events)) {
+      $loaded_events = \Drupal::entityTypeManager()->getStorage('eventinstance')->loadMultiple($events);
+      $state = \Drupal::keyValue('field_inheritance');
+      foreach ($loaded_events as $event) {
+        $entity_type = $event->getEntityTypeId();
+        $bundle = $event->bundle();
+
+        $state_key = $event->getEntityTypeId() . ':' . $event->uuid();
+        $state_values = $state->get($state_key);
+
+        $inherited_field_ids = \Drupal::entityQuery('field_inheritance')
+          ->condition('sourceEntityType', 'eventseries')
+          ->condition('destinationEntityType', $entity_type)
+          ->condition('destinationEntityBundle', $bundle)
+          ->execute();
+
+        if (!empty($inherited_field_ids)) {
+          $inherited_fields = \Drupal::entityTypeManager()->getStorage('field_inheritance')->loadMultiple($inherited_field_ids);
+          $state_values = [
+            'enabled' => TRUE,
+          ];
+          if (!empty($inherited_fields)) {
+            foreach ($inherited_fields as $inherited_field) {
+              $name = $inherited_field->idWithoutTypeAndBundle();
+              $state_values[$name] = [
+                'entity' => $event->getEventSeries()->id(),
+              ];
+            }
+          }
+        }
+        $state->set($state_key, $state_values);
+
+        $sandbox['progress']++;
+      }
+      echo 'Updated: ' . count($events) . ' event instances. Total: ' . $sandbox['progress'] . ' of ' . $sandbox['max'] . "\r\n";
+      $sandbox['#finished'] = ($sandbox['progress'] / $sandbox['max']);
+    }
+  }
+  else {
+    $sandbox['#finished'] = 1;
+    drupal_flush_all_caches();
+  }
+}
+
+/**
+ * Import new default config added for views submodule support.
+ */
+function recurring_events_update_8010() {
+  $configs = [
+    'core.entity_view_display.eventinstance.default.list',
+    'core.entity_view_mode.eventinstance.list',
+    'core.entity_view_display.eventseries.default.list',
+    'core.entity_view_mode.eventseries.list',
+  ];
+
+  foreach ($configs as $config) {
+    $path = drupal_get_path('module', 'recurring_events') . '/config/install';
+    $source = new FileStorage($path);
+    /** @var \Drupal\Core\Config\StorageInterface $active_storage */
+    $active_storage = \Drupal::service('config.storage');
+    $active_storage->write($config, $source->read($config));
+  }
+}
diff --git a/recurring_events.libraries.yml b/recurring_events.libraries.yml
index 79e065dfe9371ee747907971159c2e413feb1922..6950c953fd7aabd90b841c10333872f6ca90bc8b 100644
--- a/recurring_events.libraries.yml
+++ b/recurring_events.libraries.yml
@@ -12,4 +12,4 @@ recurring_events.date_form:
     js/recurring_events_date_form.js: {}
   dependencies:
     - core/drupal
-    - core/jquery
\ No newline at end of file
+    - core/jquery
diff --git a/recurring_events.links.action.yml b/recurring_events.links.action.yml
index a8faa12bca2b49d984891374e66fbaefa7ee073a..813d4c726755f27aa82a062adba233aaa666a98b 100644
--- a/recurring_events.links.action.yml
+++ b/recurring_events.links.action.yml
@@ -1,6 +1,6 @@
 # Add Event Series button.
-entity.eventseries.add_form:
-  route_name: entity.eventseries.add_form
+entity.eventseries.add_page:
+  route_name: entity.eventseries.add_page
   title: 'Add Event'
   appears_on:
     - entity.eventseries.admin_collection
@@ -8,13 +8,11 @@ entity.eventseries.add_form:
     - entity.eventinstance.admin_collection
     - entity.eventinstance.collection
 
-
-# Add Field Inheritance button.
-entity.field_inheritance.add_form:
-  route_name: entity.field_inheritance.add_form
-  title: 'Add Field inheritance'
+entity.eventseries_type.add_form:
+  route_name: entity.eventseries_type.add_form
+  title: 'Add Event Series Type'
   appears_on:
-    - entity.field_inheritance.collection
+    - entity.eventseries_type.collection
 
 entity.excluded_dates.add_form:
   route_name: entity.excluded_dates.add_form
diff --git a/recurring_events.links.menu.yml b/recurring_events.links.menu.yml
index 7ded46c04401cba7b7ecd2274b5f219b95519b5f..235f7216aaeffb8c8b7450c03f8913fba4270b3b 100644
--- a/recurring_events.links.menu.yml
+++ b/recurring_events.links.menu.yml
@@ -13,10 +13,10 @@ events.admin.content:
   parent: system.admin_content
 
 # Add Event page.
-eventseries.add:
+entity.eventseries.add_page:
   title: 'Add Event'
   description: 'Add a new event.'
-  route_name: entity.eventseries.add_form
+  route_name: entity.eventseries.add_page
   parent: events.admin.content
   weight: 1
 
@@ -24,7 +24,7 @@ eventseries.add:
 eventseries.listing:
   title: 'Event Series'
   description: 'Event series listing.'
-  route_name: entity.eventseries.collection
+  route_name: entity.eventseries.admin_collection
   parent: events.admin.content
   weight: 2
 
@@ -32,7 +32,7 @@ eventseries.listing:
 eventinstance.listing:
   title: 'Event Instances'
   description: 'Event instance listing.'
-  route_name: entity.eventinstance.collection
+  route_name: entity.eventinstance.admin_collection
   parent: events.admin.content
   weight: 3
 
@@ -50,4 +50,28 @@ eventinstance.admin.structure.settings:
   description: 'Configure Event Instance Entity'
   route_name:  eventinstance.settings
   parent: events.admin.overview
+  weight: 2
+
+# Events Series types admin page.
+entity.eventseries_type.collection:
+  title: 'Event Series Types'
+  description: 'Configure Event Series Types'
+  route_name: entity.eventseries_type.collection
+  parent: events.admin.overview
   weight: 1
+
+# Event Series types add page.
+entity.eventseries_type.add_form:
+  title: 'Add Series Type'
+  description: 'Add An Event Series Type'
+  route_name: entity.eventseries_type.add_form
+  parent: entity.eventseries_type.collection
+  weight: -99
+
+# Events Instance types admin page.
+entity.eventinstance_type.collection:
+  title: 'Event Instance Types'
+  description: 'Configure Event Instance Types'
+  route_name: entity.eventinstance_type.collection
+  parent: events.admin.overview
+  weight: 3
diff --git a/recurring_events.links.task.yml b/recurring_events.links.task.yml
index 6b27e3dc09a9aa6f9117e8cec1fdd91dba1008ee..00e21a83cda54d79754061c10f8e2ad3964e9273 100644
--- a/recurring_events.links.task.yml
+++ b/recurring_events.links.task.yml
@@ -94,12 +94,6 @@ entity.eventinstance.settings:
   title: Event Instance Settings
   base_route: eventinstance.settings
 
-# Field Inheritance settings admin page.
-entity.field_inheritance.collection:
-  route_name: entity.field_inheritance.collection
-  title: Field Inheritance
-  base_route: eventinstance.settings
-
 # Excluded dates settings admin page.
 entity.excluded_dates.collection:
   route_name: entity.excluded_dates.collection
@@ -110,4 +104,4 @@ entity.excluded_dates.collection:
 entity.included_dates.collection:
   route_name: entity.included_dates.collection
   title: Included dates
-  base_route: eventseries.settings
\ No newline at end of file
+  base_route: eventseries.settings
diff --git a/recurring_events.module b/recurring_events.module
index 3145ca1a5df19dc215ff108fcf20aa87921a6bb6..b305b87fc5d93e419702acf665607bab56b36806 100644
--- a/recurring_events.module
+++ b/recurring_events.module
@@ -8,14 +8,16 @@
 use Drupal\Core\Routing\RouteMatchInterface;
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Render\Element;
-use Drupal\Core\Entity\EntityTypeInterface;
-use Drupal\Core\Field\BaseFieldDefinition;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\recurring_events\Entity\EventSeries;
+use Drupal\recurring_events\EventInterface;
 use Drupal\Core\Datetime\DrupalDateTime;
 use Drupal\datetime\Plugin\Field\FieldType\DateTimeItemInterface;
 use Drupal\Core\Entity\FieldableEntityInterface;
 use Drupal\Core\Field\FieldStorageDefinitionInterface;
+use Drupal\Core\Url;
+use Drupal\Core\Link;
+use Drupal\Core\Entity\EntityForm;
 
 /**
  * Implements hook_help().
@@ -101,57 +103,6 @@ function recurring_events_help($route_name, RouteMatchInterface $route_match) {
   }
 }
 
-/**
- * Implements hook_entity_base_field_info_alter().
- */
-function recurring_events_entity_base_field_info_alter(&$fields, EntityTypeInterface $entity_type) {
-  if ($entity_type->id() === 'eventinstance') {
-    $inherited_fields = \Drupal::entityTypeManager()->getStorage('field_inheritance')->loadMultiple();
-    if (!empty($inherited_fields)) {
-      foreach ($inherited_fields as $field) {
-        $settings = [
-          'source field' => $field->sourceField(),
-          'method' => $field->type(),
-          'plugin' => $field->plugin(),
-        ];
-
-        if ($field->entityField()) {
-          $settings['entity field'] = $field->entityField();
-        }
-
-        $field_definitions = \Drupal::service('entity_field.manager')->getFieldDefinitions('eventseries', 'eventseries');
-
-        $type = 'string';
-        if (!empty($field_definitions[$field->sourceField()])) {
-          $settings = array_merge($settings, $field_definitions[$field->sourceField()]->getSettings());
-          $type = $field_definitions[$field->sourceField()]->getType();
-        }
-
-        $class = '\Drupal\recurring_events\FieldInheritanceFactory';
-        if ($field->plugin() === 'entity_reference_inheritance') {
-          $class = '\Drupal\recurring_events\EntityReferenceFieldInheritanceFactory';
-        }
-
-        // Allow developers to override the class to use for a field.
-        \Drupal::moduleHandler()->alter('recurring_events_inheritance_class', $class, $field);
-
-        $fields[$field->id()] = BaseFieldDefinition::create($type)
-          ->setLabel(t('Inherited @label', ['@label' => $field->label()]))
-          ->setName($field->id())
-          ->setDescription(t('The inherited field: @field', ['@field' => $field->label()]))
-          ->setComputed(TRUE)
-          ->setClass($class)
-          ->setSettings($settings)
-          ->setTargetEntityTypeId($entity_type->id())
-          ->setTranslatable(FALSE)
-          ->setRevisionable(FALSE)
-          ->setReadOnly(TRUE)
-          ->setDisplayConfigurable('view', TRUE);
-      }
-    }
-  }
-}
-
 /**
  * Implements hook_entity_operation().
  */
@@ -184,6 +135,10 @@ function recurring_events_theme() {
     'template' => 'eventseries',
   ];
 
+  $theme['eventseries_add_list'] = [
+    'variables' => ['content' => NULL],
+  ];
+
   return $theme;
 }
 
@@ -221,6 +176,30 @@ function template_preprocess_eventseries(array &$variables) {
   }
 }
 
+/**
+ * Prepares variables for list of available eventseries type templates.
+ *
+ * Default template: eventseries-add-list.html.twig.
+ *
+ * @param array $variables
+ *   An associative array containing:
+ *   - content: An array of eventseries types.
+ */
+function template_preprocess_eventseries_add_list(array &$variables) {
+  $variables['types'] = [];
+  if (!empty($variables['content'])) {
+    foreach ($variables['content'] as $type) {
+      $variables['types'][$type->id()] = [
+        'type' => $type->id(),
+        'add_link' => Link::fromTextAndUrl($type->label(), new Url('entity.eventseries.add_form', ['eventseries_type' => $type->id()])),
+        'description' => [
+          '#markup' => $type->getDescription(),
+        ],
+      ];
+    }
+  }
+}
+
 /**
  * Implements hook_ENTITY_TYPE_presave().
  */
@@ -253,18 +232,240 @@ function recurring_events_eventseries_insert(EntityInterface $entity) {
       if (empty($instance->eventseries_id->value)) {
         $instance->set('eventseries_id', $entity->id());
         $instance->setNewRevision(FALSE);
+
+        // Configure the field inheritances for this instance.
+        $entity_type = $instance->getEntityTypeId();
+        $bundle = $instance->bundle();
+        $inherited_field_ids = \Drupal::entityQuery('field_inheritance')
+          ->condition('sourceEntityType', 'eventseries')
+          ->condition('destinationEntityType', $entity_type)
+          ->condition('destinationEntityBundle', $bundle)
+          ->execute();
+
+        if (!empty($inherited_field_ids)) {
+          $state_key = $entity_type . ':' . $instance->uuid();
+          $state = \Drupal::keyValue('field_inheritance');
+          $state_values = $state->get($state_key);
+
+          $inherited_fields = \Drupal::entityTypeManager()->getStorage('field_inheritance')->loadMultiple($inherited_field_ids);
+          $state_values = [
+            'enabled' => TRUE,
+          ];
+          if (!empty($inherited_fields)) {
+            foreach ($inherited_fields as $inherited_field) {
+              $name = $inherited_field->idWithoutTypeAndBundle();
+              $state_values[$name] = [
+                'entity' => $instance->getEventSeries()->id(),
+              ];
+            }
+          }
+          $state->set($state_key, $state_values);
+        }
+
         $instance->save();
       }
     }
   }
 }
 
+/**
+ * Implements hook_ENTITY_TYPE_insert().
+ */
+function recurring_events_eventseries_type_insert(EntityInterface $entity) {
+  // Event series types are tied to event instance types, and optionally
+  // registrant types. Therefore, we need to create equivalent instance and
+  // registrant types every time an event series type is created.
+  $series_type_label = $entity->label();
+  $series_type_description = $entity->getDescription();
+  $series_type_id = $entity->id();
+
+  $instance_types = \Drupal::entityTypeManager()->getStorage('eventinstance_type')->load($series_type_id);
+  if (empty($instance_types)) {
+    $instance_type = \Drupal::entityTypeManager()->getStorage('eventinstance_type')->create([
+      'id' => $series_type_id,
+      'label' => $series_type_label,
+      'description' => $series_type_description,
+    ]);
+    $instance_type->save();
+
+    $instance_title = \Drupal::entityTypeManager()->getStorage('field_inheritance')->create([
+      'id' => 'title',
+      'label' => 'Title',
+      'type' => 'inherit',
+      'sourceEntityType' => 'eventseries',
+      'sourceEntityBundle' => $series_type_id,
+      'sourceField' => 'title',
+      'destinationEntityType' => 'eventinstance',
+      'destinationEntityBundle' => $series_type_id,
+      'plugin' => 'default_inheritance',
+    ]);
+    $instance_title->save();
+
+    $instance_description = \Drupal::entityTypeManager()->getStorage('field_inheritance')->create([
+      'id' => 'description',
+      'label' => 'Description',
+      'type' => 'append',
+      'sourceEntityType' => 'eventseries',
+      'sourceEntityBundle' => $series_type_id,
+      'sourceField' => 'body',
+      'destinationEntityType' => 'eventinstance',
+      'destinationEntityBundle' => $series_type_id,
+      'destinationField' => 'body',
+      'plugin' => 'default_inheritance',
+    ]);
+    $instance_description->save();
+  }
+
+  if (\Drupal::moduleHandler()->moduleExists('recurring_events_registration')) {
+    $registrant_types = \Drupal::entityTypeManager()->getStorage('registrant_type')->load($series_type_id);
+    if (empty($registrant_types)) {
+      $registrant_type = \Drupal::entityTypeManager()->getStorage('registrant_type')->create([
+        'id' => $series_type_id,
+        'label' => $series_type_label,
+        'description' => $series_type_description,
+      ]);
+      $registrant_type->save();
+    }
+  }
+
+  \Drupal::cache('menu')->invalidateAll();
+  \Drupal::service('plugin.manager.menu.link')->rebuild();
+}
+
+/**
+ * Implements hook_ENTITY_TYPE_delete().
+ */
+function recurring_events_eventseries_type_delete(EntityInterface $entity) {
+  // Event series types are tied to event instance types, and optionally
+  // registrant types. Therefore, we need to delete equivalent instance and
+  // registrant types every time an event series type is deleted. We also must
+  // delete all inheritances that use these types as either the source or the
+  // destination.
+  $query = \Drupal::entityQuery('field_inheritance');
+  $and_destination = $query->andConditionGroup()
+    ->condition('destinationEntityType', 'eventseries')
+    ->condition('destinationEntityBundle', $entity->id());
+  $and_source = $query->andConditionGroup()
+    ->condition('sourceEntityType', 'eventseries')
+    ->condition('sourceEntityBundle', $entity->id());
+  $or = $query->orConditionGroup()
+    ->condition($and_destination)
+    ->condition($and_source);
+  $query->condition($or);
+  $inherited_field_ids = $query->execute();
+
+  if (!empty($inherited_field_ids)) {
+    $inherited_fields = \Drupal::entityTypeManager()->getStorage('field_inheritance')->loadMultiple($inherited_field_ids);
+    foreach ($inherited_fields as $field) {
+      $field->delete();
+    }
+  }
+
+  $instance_type = \Drupal::entityTypeManager()->getStorage('eventinstance_type')->load($entity->id());
+  if (!empty($instance_type)) {
+    $query = \Drupal::entityQuery('field_inheritance');
+    $and_destination = $query->andConditionGroup()
+      ->condition('destinationEntityType', 'eventinstance')
+      ->condition('destinationEntityBundle', $instance_type->id());
+    $and_source = $query->andConditionGroup()
+      ->condition('sourceEntityType', 'eventinstance')
+      ->condition('sourceEntityBundle', $instance_type->id());
+    $or = $query->orConditionGroup()
+      ->condition($and_destination)
+      ->condition($and_source);
+    $query->condition($or);
+    $inherited_field_ids = $query->execute();
+
+    if (!empty($inherited_field_ids)) {
+      $inherited_fields = \Drupal::entityTypeManager()->getStorage('field_inheritance')->loadMultiple($inherited_field_ids);
+      foreach ($inherited_fields as $field) {
+        $field->delete();
+      }
+    }
+    $instance_type->delete();
+  }
+
+  if (\Drupal::moduleHandler()->moduleExists('recurring_events_registration')) {
+    $registrant_type = \Drupal::entityTypeManager()->getStorage('registrant_type')->load($entity->id());
+    if (!empty($registrant_type)) {
+      $query = \Drupal::entityQuery('field_inheritance');
+      $and_destination = $query->andConditionGroup()
+        ->condition('destinationEntityType', 'registrant')
+        ->condition('destinationEntityBundle', $registrant_type->id());
+      $and_source = $query->andConditionGroup()
+        ->condition('sourceEntityType', 'registrant')
+        ->condition('sourceEntityBundle', $registrant_type->id());
+      $or = $query->orConditionGroup()
+        ->condition($and_destination)
+        ->condition($and_source);
+      $query->condition($or);
+      $inherited_field_ids = $query->execute();
+
+      if (!empty($inherited_field_ids)) {
+        $inherited_fields = \Drupal::entityTypeManager()->getStorage('field_inheritance')->loadMultiple($inherited_field_ids);
+        foreach ($inherited_fields as $field) {
+          $field->delete();
+        }
+      }
+      $registrant_type->delete();
+    }
+  }
+}
+
+/**
+ * Implements hook_entity_operation_alter().
+ */
+function recurring_events_entity_operation_alter(array &$operations, EntityInterface $entity) {
+  if ($entity->getEntityTypeId() == 'eventinstance_type') {
+    if (!empty($operations['delete'])) {
+      unset($operations['delete']);
+    }
+  }
+}
+
+/**
+ * Implements hook_form_alter().
+ */
+function recurring_events_form_alter(&$form, FormStateInterface $form_state, $form_id) {
+  $form_object = $form_state->getFormObject();
+  if (!empty($form_object) && $form_object instanceof EntityForm) {
+    $entity = $form_state->getFormObject()->getEntity();
+    if (!empty($entity) && $entity instanceof FieldableEntityInterface && strpos($form['#id'], 'delete') === FALSE) {
+      $entity_type = $entity->getEntityTypeId();
+      $bundle = $entity->bundle();
+      if ($entity_type == 'eventinstance') {
+        $series = $entity->getEventSeries();
+        $inherited_field_ids = \Drupal::entityQuery('field_inheritance')
+          ->condition('destinationEntityType', $entity_type)
+          ->condition('destinationEntityBundle', $bundle)
+          ->execute();
+
+        if (!empty($inherited_field_ids)) {
+          $state_key = $entity->getEntityTypeId() . ':' . $entity->uuid();
+          $state = \Drupal::keyValue('field_inheritance');
+          $state_values = $state->get($state_key);
+
+          $inherited_fields = \Drupal::entityTypeManager()->getStorage('field_inheritance')->loadMultiple($inherited_field_ids);
+          if (!isset($state_values['enabled'])) {
+            $form['field_inheritance']['field_inheritance_enable']['#default_value'] = TRUE;
+          }
+          foreach ($inherited_fields as $field) {
+            if (!isset($state_values[$field->idWithoutTypeAndBundle()]) && !isset($state_values[$field->idWithoutTypeAndBundle()]['skip'])) {
+              $form['field_inheritance']['fields']['field_inheritance_' . $field->idWithoutTypeAndBundle()]['field_inheritance_field_entity_' . $field->idWithoutTypeAndBundle()]['#default_value'] = $series;
+            }
+          }
+        }
+      }
+    }
+  }
+}
+
 /**
  * Implements hook_form_FORM_ID_alter().
  */
 function recurring_events_form_content_moderation_entity_moderation_form_alter(&$form, FormStateInterface $form_state) {
   $entity = $form_state->get('entity');
-  if ($entity->getEntityTypeId() === 'eventseries') {
+  if ($entity instanceof EventInterface && $entity->getEntityTypeId() === 'eventseries') {
     $original = \Drupal::entityTypeManager()->getStorage('eventseries')->load($entity->id());
     $creation_service = \Drupal::service('recurring_events.event_creation_service');
     if ($creation_service->checkForOriginalRecurConfigChanges($entity, $original)) {
@@ -391,12 +592,12 @@ function recurring_events_recurring_events_event_instances_pre_create_alter(arra
       $end = $dates['end_date']->getTimestamp();
 
       for ($x = 0; $x < (count($include) - 1); $x++) {
-        $include_start = DrupalDateTime::createFromFormat(DateTimeItemInterface::DATETIME_STORAGE_FORMAT, $include[$x]['value'] . 'T00:00:00');
-        $include_start = $include_start->getTimestamp();
+        $included_start = DrupalDateTime::createFromFormat(DateTimeItemInterface::DATETIME_STORAGE_FORMAT, $include[$x]['value'] . 'T00:00:00');
+        $included_start = $included_start->getTimestamp();
         $included_end = DrupalDateTime::createFromFormat(DateTimeItemInterface::DATETIME_STORAGE_FORMAT, $include[$x]['end_value'] . 'T23:59:59');
         $included_end = $included_end->getTimestamp();
 
-        if ($start >= $include_start && $start <= $included_end && $end >= $included_start && $end <= $included_end) {
+        if ($start >= $included_start && $start <= $included_end && $end >= $included_start && $end <= $included_end) {
           // This event is in the inclusion range, so move on to the next one.
           break;
         }
@@ -419,7 +620,7 @@ function recurring_events_recurring_events_event_instances_pre_create_alter(arra
 function recurring_events_allowed_values_function(FieldStorageDefinitionInterface $definition, FieldableEntityInterface $entity = NULL) {
   $values = ['custom' => t('Custom Event')];
   $fields = \Drupal::service('entity_field.manager')->getBaseFieldDefinitions('eventseries');
-  foreach ($fields as $field_name => $field) {
+  foreach ($fields as $field) {
     $field_definition = \Drupal::service('plugin.manager.field.field_type')->getDefinition($field->getType());
     $class = new \ReflectionClass($field_definition['class']);
     if ($class->implementsInterface('\Drupal\recurring_events\RecurringEventsFieldTypeInterface')) {
@@ -443,3 +644,35 @@ function recurring_events_recurring_events_recur_field_types_alter(&$fields) {
     }
   }
 }
+
+/**
+ * Implements hook_theme_suggestions_HOOK().
+ */
+function recurring_events_theme_suggestions_eventseries(array $variables) {
+  $suggestions = [];
+  $entity = $variables['elements']['#eventseries'];
+  $sanitized_view_mode = strtr($variables['elements']['#view_mode'], '.', '_');
+
+  $suggestions[] = 'eventseries__' . $sanitized_view_mode;
+  $suggestions[] = 'eventseries__' . $entity->bundle();
+  $suggestions[] = 'eventseries__' . $entity->bundle() . '__' . $sanitized_view_mode;
+  $suggestions[] = 'eventseries__' . $entity->id();
+  $suggestions[] = 'eventseries__' . $entity->id() . '__' . $sanitized_view_mode;
+  return $suggestions;
+}
+
+/**
+ * Implements hook_theme_suggestions_HOOK().
+ */
+function recurring_events_theme_suggestions_eventinstance(array $variables) {
+  $suggestions = [];
+  $entity = $variables['elements']['#eventinstance'];
+  $sanitized_view_mode = strtr($variables['elements']['#view_mode'], '.', '_');
+
+  $suggestions[] = 'eventinstance__' . $sanitized_view_mode;
+  $suggestions[] = 'eventinstance__' . $entity->bundle();
+  $suggestions[] = 'eventinstance__' . $entity->bundle() . '__' . $sanitized_view_mode;
+  $suggestions[] = 'eventinstance__' . $entity->id();
+  $suggestions[] = 'eventinstance__' . $entity->id() . '__' . $sanitized_view_mode;
+  return $suggestions;
+}
diff --git a/recurring_events.permissions.yml b/recurring_events.permissions.yml
index 922f473387ad302f45665b8ac9c0ecb8c0a2b7c6..76e212749bea2864d75e1bc0e1ba3dfa9496db93 100644
--- a/recurring_events.permissions.yml
+++ b/recurring_events.permissions.yml
@@ -77,4 +77,16 @@ access eventseries overview:
 # Event Instance Administration.
 access eventinstance overview:
   title: 'Access the eventinstance overview page'
-  description: 'View the table view of eventinstance'
\ No newline at end of file
+  description: 'View the table view of eventinstance'
+
+# Event Series Types Administration.
+administer eventseries types:
+  title: 'Administer eventseries types'
+  description: 'Manage types of eventseries.'
+  restrict access: true
+
+# Event Instance Types Administration.
+administer eventinstance types:
+  title: 'Administer eventinstance types'
+  description: 'Manage types of eventinstance.'
+  restrict access: true
diff --git a/recurring_events.routing.yml b/recurring_events.routing.yml
index 3333a2503d1c88c449c2f56be74153a0076fb8b8..e23c6d1f61c374d1bbef0bccebb34c049a9e46d3 100644
--- a/recurring_events.routing.yml
+++ b/recurring_events.routing.yml
@@ -14,10 +14,23 @@ entity.eventseries.canonical:
 
 # Add an EventSeries.
 entity.eventseries.add_form:
-  path: '/events/add'
+  path: '/events/add/{eventseries_type}'
   defaults:
     _entity_form: eventseries.add
-    _title: 'Add Event'
+    _title_callback: '\Drupal\recurring_events\Controller\EventSeriesController::addPageTitle'
+  requirements:
+    _entity_create_access: 'eventseries'
+  options:
+    parameters:
+      eventseries_type:
+        type: entity:eventseries_type
+
+# Add an EventSeries.
+entity.eventseries.add_page:
+  path: '/events/add'
+  defaults:
+    _title: 'Add event'
+    _controller: '\Drupal\recurring_events\Controller\EventSeriesController::addPage'
   requirements:
     _entity_create_access: 'eventseries'
 
@@ -26,7 +39,7 @@ entity.eventseries.edit_form:
   path: '/events/series/{eventseries}/edit'
   defaults:
     _entity_form: eventseries.edit
-    _title: 'Edit Event Series'
+    _title_callback: '\Drupal\recurring_events\Controller\EventSeriesController::editPageTitle'
   requirements:
     _entity_access: 'eventseries.edit'
     eventseries: \d+
@@ -40,7 +53,7 @@ entity.eventseries.delete_form:
   path: '/events/series/{eventseries}/delete'
   defaults:
     _entity_form: eventseries.delete
-    _title: 'Delete Event'
+    _title_callback: '\Drupal\recurring_events\Controller\EventSeriesController::deletePageTitle'
   requirements:
     _entity_access: 'eventseries.delete'
     eventseries: \d+
@@ -54,7 +67,7 @@ entity.eventseries.clone_form:
   path: '/events/series/{eventseries}/clone'
   defaults:
     _entity_form: eventseries.clone
-    _title: 'Clone Event Series'
+    _title_callback: '\Drupal\recurring_events\Controller\EventSeriesController::clonePageTitle'
   requirements:
     _entity_access: 'eventseries.clone'
     eventseries: \d+
@@ -187,6 +200,8 @@ entity.eventseries.admin_collection:
   requirements:
   # Checks for permission directly.
     _permission: 'access eventseries overview'
+  options:
+    _admin_route: TRUE
 
 # Event Series admin table list route.
 entity.eventinstance.admin_collection:
@@ -196,4 +211,28 @@ entity.eventinstance.admin_collection:
     _title: 'Event Instances'
   requirements:
   # Checks for permission directly.
-    _permission: 'access eventinstance overview'
\ No newline at end of file
+    _permission: 'access eventinstance overview'
+  options:
+    _admin_route: TRUE
+
+# Event Series types route.
+entity.eventseries_type.collection:
+  path: '/admin/structure/events/series/types'
+  defaults:
+    _entity_list: 'eventseries_type'
+    _title: 'Event Series types'
+  requirements:
+    _permission: 'administer eventseries types'
+  options:
+    _admin_route: TRUE
+
+# Event Instance types route.
+entity.eventinstance_type.collection:
+  path: '/admin/structure/events/instance/types'
+  defaults:
+    _entity_list: 'eventinstance_type'
+    _title: 'Event Instance types'
+  requirements:
+    _permission: 'administer eventinstance types'
+  options:
+    _admin_route: TRUE
diff --git a/recurring_events.services.yml b/recurring_events.services.yml
index 7f36cbbac181ab108207793fa8504d46c7766e96..41b953f28323dec97a740195de625ee97094886d 100644
--- a/recurring_events.services.yml
+++ b/recurring_events.services.yml
@@ -1,7 +1,4 @@
 services:
   recurring_events.event_creation_service:
     class: Drupal\recurring_events\EventCreationService
-    arguments: ['@string_translation', '@database', '@logger.factory', '@messenger', '@plugin.manager.field.field_type', '@entity_field.manager']
-  plugin.manager.field_inheritance:
-    class: Drupal\recurring_events\FieldInheritancePluginManager
-    parent: default_plugin_manager
+    arguments: ['@string_translation', '@database', '@logger.factory', '@messenger', '@plugin.manager.field.field_type', '@entity_field.manager', '@module_handler', '@entity_type.manager']
diff --git a/recurring_events.tokens.inc b/recurring_events.tokens.inc
index 3008e86540817e044c88838d613f0b4ef7b88925..95dcb9350d829c7fa4aabef871585da81b7a2a95 100644
--- a/recurring_events.tokens.inc
+++ b/recurring_events.tokens.inc
@@ -81,7 +81,7 @@ function recurring_events_tokens($type, $tokens, array $data, array $options, Bu
   if ($type == 'eventinstance' && !empty($data['eventinstance'])) {
     $event_instance = $data['eventinstance'];
     $date_format = \Drupal::config('recurring_events.eventinstance.config')->get('date_format');
-    $timezone = new \DateTimeZone(drupal_get_user_timezone());
+    $timezone = new \DateTimeZone(date_default_timezone_get());
     foreach ($tokens as $name => $original) {
       switch ($name) {
         case 'title':
diff --git a/recurring_events.views.inc b/recurring_events.views.inc
index f64c0b95dfa95f4c180c4470454a227c36da0ecc..a7d37d7fd0a70214756843ad3e3394029e232215 100644
--- a/recurring_events.views.inc
+++ b/recurring_events.views.inc
@@ -29,30 +29,22 @@ function recurring_events_views_data_alter(array &$data) {
     ],
   ];
 
-  // Create a views field for each of the inherited fields.
-  $inherited_fields = \Drupal::entityTypeManager()->getStorage('field_inheritance')->loadMultiple();
-  $set = FALSE;
-  if (!empty($inherited_fields)) {
-    foreach ($inherited_fields as $field) {
-      if ($field->id() == 'title') {
-        $data['eventinstance_field_data']['table']['base']['defaults']['field'] = 'title';
-        $set = TRUE;
-      }
-      $data['eventinstance_field_data'][$field->id()] = [
-        'title' => $field->label(),
-        'field' => [
-          'title' => $field->label(),
-          'help' => t('The inherited @field field', [
-            '@field' => $field->label(),
-          ]),
-          'id' => 'inherited_field',
-          'field_name' => $field->id(),
-        ],
-      ];
-    }
-  }
+  // Set the default field for a view based on eventinstances.
+  $data['eventinstance_field_data']['table']['base']['defaults']['field'] = 'id';
 
-  if (!$set) {
-    $data['eventinstance_field_data']['table']['base']['defaults']['field'] = 'id';
-  }
+  // @todo Remove these declarations when
+  // https://www.drupal.org/project/drupal/issues/2489476 is resolved.
+  $data['eventinstance_field_data']['date__value']['filter']['id'] = 'datetime';
+  $data['eventinstance_field_data']['date__value']['filter']['field_name'] = 'date';
+  $data['eventinstance_field_data']['date__value']['sort']['id'] = 'datetime';
+  $data['eventinstance_field_data']['date__value']['sort']['field_name'] = 'date';
+  $data['eventinstance_field_data']['date__value']['argument']['id'] = 'datetime';
+  $data['eventinstance_field_data']['date__value']['argument']['field_name'] = 'date';
+
+  $data['eventinstance_field_data']['date__end_value']['filter']['id'] = 'datetime';
+  $data['eventinstance_field_data']['date__end_value']['filter']['field_name'] = 'date';
+  $data['eventinstance_field_data']['date__end_value']['sort']['id'] = 'datetime';
+  $data['eventinstance_field_data']['date__end_value']['sort']['field_name'] = 'date';
+  $data['eventinstance_field_data']['date__end_value']['argument']['id'] = 'datetime';
+  $data['eventinstance_field_data']['date__end_value']['argument']['field_name'] = 'date';
 }
diff --git a/src/Annotation/FieldInheritance.php b/src/Annotation/FieldInheritance.php
deleted file mode 100644
index bfaa78fbe138c6924897a354bde718522926ab62..0000000000000000000000000000000000000000
--- a/src/Annotation/FieldInheritance.php
+++ /dev/null
@@ -1,37 +0,0 @@
-<?php
-
-namespace Drupal\recurring_events\Annotation;
-
-use Drupal\Component\Annotation\Plugin;
-
-/**
- * Defines a field inheritance plugin annotation object.
- *
- * @Annotation
- */
-class FieldInheritance extends Plugin {
-
-  /**
-   * The plugin ID.
-   *
-   * @var string
-   */
-  public $id;
-
-  /**
-   * The name of the form plugin.
-   *
-   * @var \Drupal\Core\Annotation\Translation
-   *
-   * @ingroup plugin_translatable
-   */
-  public $name;
-
-  /**
-   * An array of field types the inheritance plugin supports.
-   *
-   * @var array
-   */
-  public $types = [];
-
-}
diff --git a/src/Controller/EventInstanceController.php b/src/Controller/EventInstanceController.php
index 45bcdb0c86f925c336fbbba740e254597dc113e6..14965a98ba19311b185abc8ea16e9c4d7e6886c7 100644
--- a/src/Controller/EventInstanceController.php
+++ b/src/Controller/EventInstanceController.php
@@ -96,9 +96,17 @@ class EventInstanceController extends ControllerBase implements ContainerInjecti
    *   The title of the page.
    */
   public function getTitle(EventInterface $eventinstance) {
-    $title = $eventinstance->title->value;
+    $title = '';
+    $value = $eventinstance->get('title')->getValue();
+    if (!empty($value[0]['value'])) {
+      $title = $value[0]['value'];
+    }
+
     if ($eventinstance->hasTranslation($this->langCode)) {
-      $title = $eventinstance->getTranslation($this->langCode)->title->value;
+      $value = $eventinstance->getTranslation($this->langCode)->get('title')->getValue();
+      if (!empty($value[0]['value'])) {
+        $title = $value[0]['value'];
+      }
     }
     return $title;
   }
diff --git a/src/Controller/EventSeriesController.php b/src/Controller/EventSeriesController.php
index 1b495b185809d6b23fcc15ec918c0b985e1802de..75a95fe76645122502532e1be58b2f781b5ec189 100644
--- a/src/Controller/EventSeriesController.php
+++ b/src/Controller/EventSeriesController.php
@@ -12,6 +12,7 @@ use Drupal\recurring_events\EventInterface;
 use Drupal\Component\Utility\Xss;
 use Drupal\Core\Url;
 use Drupal\Core\Link;
+use Drupal\recurring_events\Entity\EventSeriesTypeInterface;
 
 /**
  * The EventSeriesController class.
@@ -80,6 +81,124 @@ class EventSeriesController extends ControllerBase implements ContainerInjection
     return $this->systemManager->getBlockContents();
   }
 
+  /**
+   * Displays add content links for available event series types.
+   *
+   * Redirects to events/add/[type] if only one type is available.
+   *
+   * @return array|\Symfony\Component\HttpFoundation\RedirectResponse
+   *   A render array for a list of the node types that can be added; however,
+   *   if there is only one node type defined for the site, the function
+   *   will return a RedirectResponse to the node add page for that one node
+   *   type.
+   */
+  public function addPage() {
+    $build = [
+      '#theme' => 'eventseries_add_list',
+      '#cache' => [
+        'tags' => $this->entityTypeManager()->getDefinition('eventseries_type')->getListCacheTags(),
+      ],
+    ];
+
+    $content = [];
+
+    // Only use eventseries types the user has access to.
+    foreach ($this->entityTypeManager()->getStorage('eventseries_type')->loadMultiple() as $type) {
+      $access = $this->entityTypeManager()->getAccessControlHandler('eventseries')->createAccess($type->id(), NULL, [], TRUE);
+      if ($access->isAllowed()) {
+        $content[$type->id()] = $type;
+      }
+      $this->renderer->addCacheableDependency($build, $access);
+    }
+
+    // Bypass the node/add listing if only one content type is available.
+    if (count($content) == 1) {
+      $type = array_shift($content);
+      return $this->redirect('entity.eventseries.add_form', ['eventseries_type' => $type->id()]);
+    }
+
+    $build['#content'] = $content;
+
+    return $build;
+  }
+
+  /**
+   * Create a new event.
+   *
+   * @param \Drupal\recurring_events\Entity\EventSeriesTypeInterface $eventseries_type
+   *   The eventseries type.
+   */
+  public function add(EventSeriesTypeInterface $eventseries_type) {
+    $eventseries = $this->entityTypeManager()->getStorage('eventseries')->create([
+      'type' => $eventseries_type->id(),
+    ]);
+
+    $form = $this->entityFormBuilder()->getForm($eventseries);
+
+    return $form;
+  }
+
+  /**
+   * The _title_callback for the entity.eventseries.add_form route.
+   *
+   * @param \Drupal\recurring_events\Entity\EventSeriesTypeInterface $eventseries_type
+   *   The eventseries type.
+   *
+   * @return string
+   *   The page title.
+   */
+  public function addPageTitle(EventSeriesTypeInterface $eventseries_type) {
+    return $this->t('Create %name Event', ['%name' => $eventseries_type->label()]);
+  }
+
+  /**
+   * The _title_callback for the entity.eventseries.edit_form route.
+   *
+   * @param \Drupal\recurring_events\EventInterface $eventseries
+   *   The eventseries type.
+   *
+   * @return string
+   *   The page title.
+   */
+  public function editPageTitle(EventInterface $eventseries) {
+    return $this->t('Edit %type Event %title', [
+      '%type' => $eventseries->bundle(),
+      '%title' => $eventseries->label(),
+    ]);
+  }
+
+  /**
+   * The _title_callback for the entity.eventseries.delete_form route.
+   *
+   * @param \Drupal\recurring_events\EventInterface $eventseries
+   *   The eventseries type.
+   *
+   * @return string
+   *   The page title.
+   */
+  public function deletePageTitle(EventInterface $eventseries) {
+    return $this->t('Delete %type Event %title', [
+      '%type' => $eventseries->bundle(),
+      '%title' => $eventseries->label(),
+    ]);
+  }
+
+  /**
+   * The _title_callback for the entity.eventseries.clone_form route.
+   *
+   * @param \Drupal\recurring_events\EventInterface $eventseries
+   *   The eventseries type.
+   *
+   * @return string
+   *   The page title.
+   */
+  public function clonePageTitle(EventInterface $eventseries) {
+    return $this->t('Clone %type Event %title', [
+      '%type' => $eventseries->bundle(),
+      '%title' => $eventseries->label(),
+    ]);
+  }
+
   /**
    * Displays an eventseries revision.
    *
diff --git a/src/Entity/EventInstance.php b/src/Entity/EventInstance.php
index 2b93988e92512df862d25fc3e586c6ac01714afa..095cb3f482f1f7df601903133a93ba739bdae306 100644
--- a/src/Entity/EventInstance.php
+++ b/src/Entity/EventInstance.php
@@ -96,13 +96,15 @@ use Drupal\user\UserInterface;
  *   translatable = TRUE,
  *   admin_permission = "administer eventinstance entity",
  *   fieldable = TRUE,
+ *   bundle_entity_type = "eventinstance_type",
  *   entity_keys = {
  *     "id" = "id",
  *     "revision" = "vid",
  *     "published" = "status",
  *     "langcode" = "langcode",
  *     "uuid" = "uuid",
- *     "label" = "title"
+ *     "label" = "title",
+ *     "bundle" = "type",
  *   },
  *   revision_metadata_keys = {
  *     "revision_user" = "revision_uid",
@@ -122,7 +124,7 @@ use Drupal\user\UserInterface;
  *     "revision_delete" = "/events/{eventinstance}/revisions/{eventinstance_revision}/delete",
  *     "translation_revert" = "/events/{eventinstance}/revisions/{eventinstance_revision}/revert/{langcode}",
  *   },
- *   field_ui_base_route = "eventinstance.settings",
+ *   field_ui_base_route = "entity.eventinstance_type.edit_form",
  * )
  *
  * The 'links' above are defined by their path. For core to find the
@@ -203,6 +205,13 @@ class EventInstance extends EditorialContentEntityBase implements EventInterface
     }
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function getType() {
+    return $this->bundle();
+  }
+
   /**
    * {@inheritdoc}
    */
@@ -270,21 +279,6 @@ class EventInstance extends EditorialContentEntityBase implements EventInterface
     return $this;
   }
 
-  /**
-   * {@inheritdoc}
-   */
-  public function getRevisionAuthor() {
-    return $this->getRevisionUser();
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function setRevisionAuthorId($uid) {
-    $this->setRevisionUserId($uid);
-    return $this;
-  }
-
   /**
    * {@inheritdoc}
    *
@@ -318,6 +312,7 @@ class EventInstance extends EditorialContentEntityBase implements EventInterface
           'match_operator' => 'CONTAINS',
           'size' => '60',
           'placeholder' => '',
+          'match_limit' => 10,
         ],
       ])
       ->setDisplayConfigurable('form', TRUE);
@@ -328,6 +323,12 @@ class EventInstance extends EditorialContentEntityBase implements EventInterface
       ->setDescription(t('The UUID of the event entity.'))
       ->setReadOnly(TRUE);
 
+    $fields['type'] = BaseFieldDefinition::create('entity_reference')
+      ->setLabel(t('Type'))
+      ->setDescription(t('The eventinstance type.'))
+      ->setSetting('target_type', 'eventinstance_type')
+      ->setReadOnly(TRUE);
+
     $fields['body'] = BaseFieldDefinition::create('text_long')
       ->setLabel(t('Body'))
       ->setTranslatable(TRUE)
@@ -388,7 +389,7 @@ class EventInstance extends EditorialContentEntityBase implements EventInterface
         'settings' => [
           'display_label' => TRUE,
         ],
-        'weight' => 120,
+        'weight' => 12,
       ])
       ->setDisplayConfigurable('form', TRUE);
 
diff --git a/src/Entity/EventInstanceType.php b/src/Entity/EventInstanceType.php
new file mode 100644
index 0000000000000000000000000000000000000000..3167b860d29a0f5b4ca639d055c553c80611140f
--- /dev/null
+++ b/src/Entity/EventInstanceType.php
@@ -0,0 +1,80 @@
+<?php
+
+namespace Drupal\recurring_events\Entity;
+
+use Drupal\Core\Config\Entity\ConfigEntityBundleBase;
+
+/**
+ * Defines the Event instance type entity.
+ *
+ * @ConfigEntityType(
+ *   id = "eventinstance_type",
+ *   label = @Translation("Event instance type"),
+ *   handlers = {
+ *     "view_builder" = "Drupal\Core\Entity\EntityViewBuilder",
+ *     "list_builder" = "Drupal\recurring_events\EventInstanceTypeListBuilder",
+ *     "form" = {
+ *       "edit" = "Drupal\recurring_events\Form\EventInstanceTypeForm",
+ *     },
+ *     "route_provider" = {
+ *       "html" = "Drupal\recurring_events\EventInstanceTypeHtmlRouteProvider",
+ *     },
+ *   },
+ *   config_prefix = "eventinstance_type",
+ *   bundle_of = "eventinstance",
+ *   admin_permission = "administer eventinstance entity",
+ *   entity_keys = {
+ *     "id" = "id",
+ *     "label" = "label",
+ *     "uuid" = "uuid"
+ *   },
+ *   links = {
+ *     "canonical" = "/admin/structure/events/instance/types/eventinstance_type/{eventinstance_type}",
+ *     "edit-form" = "/admin/structure/events/instance/types/eventinstance_type/{eventinstance_type}/edit",
+ *     "collection" = "/admin/structure/events/instance/types/eventinstance_type"
+ *   },
+ *   config_export = {
+ *     "label",
+ *     "id",
+ *     "description",
+ *   }
+ * )
+ */
+class EventInstanceType extends ConfigEntityBundleBase implements EventInstanceTypeInterface {
+
+  /**
+   * The Event instance type ID.
+   *
+   * @var string
+   */
+  protected $id;
+
+  /**
+   * The Event instance type label.
+   *
+   * @var string
+   */
+  protected $label;
+
+  /**
+   * A brief description of this eventinstance type.
+   *
+   * @var string
+   */
+  protected $description;
+
+  /**
+   * {@inheritdoc}
+   */
+  public function id() {
+    return $this->id;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getDescription() {
+    return $this->description;
+  }
+
+}
diff --git a/src/Entity/EventInstanceTypeInterface.php b/src/Entity/EventInstanceTypeInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..fdfabb02594397b99a946716e57bf92f5148fbc8
--- /dev/null
+++ b/src/Entity/EventInstanceTypeInterface.php
@@ -0,0 +1,20 @@
+<?php
+
+namespace Drupal\recurring_events\Entity;
+
+use Drupal\Core\Config\Entity\ConfigEntityInterface;
+
+/**
+ * Provides an interface for defining Event instance type entities.
+ */
+interface EventInstanceTypeInterface extends ConfigEntityInterface {
+
+  /**
+   * Gets the description.
+   *
+   * @return string
+   *   The description of this eventinstance type.
+   */
+  public function getDescription();
+
+}
diff --git a/src/Entity/EventSeries.php b/src/Entity/EventSeries.php
index c1573172de32d88dc3d1a637062ca20c9558cf32..024b78e858ffc35fe3f866d43b8d792580faffa9 100644
--- a/src/Entity/EventSeries.php
+++ b/src/Entity/EventSeries.php
@@ -96,13 +96,15 @@ use Drupal\user\UserInterface;
  *   translatable = TRUE,
  *   admin_permission = "administer eventseries entity",
  *   fieldable = TRUE,
+ *   bundle_entity_type = "eventseries_type",
  *   entity_keys = {
  *     "id" = "id",
  *     "revision" = "vid",
  *     "published" = "status",
  *     "langcode" = "langcode",
  *     "label" = "title",
- *     "uuid" = "uuid"
+ *     "uuid" = "uuid",
+ *     "bundle" = "type",
  *   },
  *   revision_metadata_keys = {
  *     "revision_user" = "revision_uid",
@@ -111,6 +113,8 @@ use Drupal\user\UserInterface;
  *   },
  *   links = {
  *     "canonical" = "/events/series/{eventseries}",
+ *     "add-page" = "/events/add",
+ *     "add-form" = "/events/add/{eventseries_type}",
  *     "edit-form" = "/events/series/{eventseries}/edit",
  *     "delete-form" = "/events/series/{eventseries}/delete",
  *     "collection" = "/events/series",
@@ -122,7 +126,7 @@ use Drupal\user\UserInterface;
  *     "revision_delete" = "/events/series/{eventseries}/revisions/{eventseries_revision}/delete",
  *     "translation_revert" = "/events/series/{eventseries}/revisions/{eventseries_revision}/revert/{langcode}",
  *   },
- *   field_ui_base_route = "eventseries.settings",
+ *   field_ui_base_route = "entity.eventseries_type.edit_form",
  * )
  *
  * The 'links' above are defined by their path. For core to find the
@@ -202,6 +206,13 @@ class EventSeries extends EditorialContentEntityBase implements EventInterface {
     }
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function getType() {
+    return $this->bundle();
+  }
+
   /**
    * {@inheritdoc}
    */
@@ -269,21 +280,6 @@ class EventSeries extends EditorialContentEntityBase implements EventInterface {
     return $this;
   }
 
-  /**
-   * {@inheritdoc}
-   */
-  public function getRevisionAuthor() {
-    return $this->getRevisionUser();
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function setRevisionAuthorId($uid) {
-    $this->setRevisionUserId($uid);
-    return $this;
-  }
-
   /**
    * {@inheritdoc}
    *
@@ -311,11 +307,12 @@ class EventSeries extends EditorialContentEntityBase implements EventInterface {
       ->setTranslatable(TRUE)
       ->setDisplayOptions('form', [
         'type' => 'entity_reference_autocomplete',
-        'weight' => 5,
+        'weight' => 11,
         'settings' => [
           'match_operator' => 'CONTAINS',
           'size' => '60',
           'placeholder' => '',
+          'match_limit' => 10,
         ],
       ])
       ->setDisplayConfigurable('form', TRUE);
@@ -325,6 +322,12 @@ class EventSeries extends EditorialContentEntityBase implements EventInterface {
       ->setDescription(t('The UUID of the event entity.'))
       ->setReadOnly(TRUE);
 
+    $fields['type'] = BaseFieldDefinition::create('entity_reference')
+      ->setLabel(t('Type'))
+      ->setDescription(t('The eventseries type.'))
+      ->setSetting('target_type', 'eventseries_type')
+      ->setReadOnly(TRUE);
+
     // Title field for the event.
     $fields['title'] = BaseFieldDefinition::create('string')
       ->setLabel(t('Title'))
@@ -336,11 +339,11 @@ class EventSeries extends EditorialContentEntityBase implements EventInterface {
       ])
       ->setDisplayOptions('form', [
         'type' => 'string_textfield',
-        'weight' => -6,
+        'weight' => 0,
       ])
       ->setDisplayOptions('view', [
         'label' => 'above',
-        'weight' => 10,
+        'weight' => 0,
       ])
       ->setDisplayConfigurable('form', TRUE)
       ->setDisplayConfigurable('view', TRUE)
@@ -356,11 +359,11 @@ class EventSeries extends EditorialContentEntityBase implements EventInterface {
       ->setDisplayConfigurable('view', TRUE)
       ->setDisplayOptions('form', [
         'type' => 'text_textarea',
-        'weight' => -4,
+        'weight' => 1,
       ])
       ->setDisplayOptions('view', [
         'label' => 'above',
-        'weight' => 10,
+        'weight' => 1,
       ])
       ->setDisplayConfigurable('form', TRUE);
 
@@ -376,11 +379,11 @@ class EventSeries extends EditorialContentEntityBase implements EventInterface {
       ->setSetting('allowed_values_function', 'recurring_events_allowed_values_function')
       ->setDisplayOptions('form', [
         'type' => 'options_buttons',
-        'weight' => 0,
+        'weight' => 2,
       ])
       ->setDisplayOptions('view', [
         'label' => 'above',
-        'weight' => 10,
+        'weight' => 2,
       ]);
 
     $fields['consecutive_recurring_date'] = BaseFieldDefinition::create('consecutive_recurring_date')
@@ -394,7 +397,7 @@ class EventSeries extends EditorialContentEntityBase implements EventInterface {
       ->setRequired(FALSE)
       ->setDisplayOptions('form', [
         'type' => 'consecutive_recurring_date',
-        'weight' => 1,
+        'weight' => 3,
       ]);
 
     $fields['daily_recurring_date'] = BaseFieldDefinition::create('daily_recurring_date')
@@ -408,7 +411,7 @@ class EventSeries extends EditorialContentEntityBase implements EventInterface {
       ->setRequired(FALSE)
       ->setDisplayOptions('form', [
         'type' => 'daily_recurring_date',
-        'weight' => 2,
+        'weight' => 4,
       ]);
 
     $fields['weekly_recurring_date'] = BaseFieldDefinition::create('weekly_recurring_date')
@@ -422,7 +425,7 @@ class EventSeries extends EditorialContentEntityBase implements EventInterface {
       ->setRequired(FALSE)
       ->setDisplayOptions('form', [
         'type' => 'weekly_recurring_date',
-        'weight' => 3,
+        'weight' => 5,
       ]);
 
     $fields['monthly_recurring_date'] = BaseFieldDefinition::create('monthly_recurring_date')
@@ -436,7 +439,7 @@ class EventSeries extends EditorialContentEntityBase implements EventInterface {
       ->setRequired(FALSE)
       ->setDisplayOptions('form', [
         'type' => 'monthly_recurring_date',
-        'weight' => 4,
+        'weight' => 6,
       ]);
 
     $fields['custom_date'] = BaseFieldDefinition::create('daterange')
@@ -450,8 +453,7 @@ class EventSeries extends EditorialContentEntityBase implements EventInterface {
       ->setRequired(FALSE)
       ->setDisplayOptions('form', [
         'type' => 'daterange_default',
-        'label' => 'above',
-        'weight' => 5,
+        'weight' => 7,
       ]);
 
     $fields['excluded_dates'] = BaseFieldDefinition::create('daterange')
@@ -466,8 +468,7 @@ class EventSeries extends EditorialContentEntityBase implements EventInterface {
       ->setSetting('datetime_type', 'date')
       ->setDisplayOptions('form', [
         'type' => 'daterange_default',
-        'label' => 'above',
-        'weight' => 6,
+        'weight' => 8,
         'settings' => [
           'format_type' => 'html_date',
           'datetime_type' => 'date',
@@ -486,8 +487,7 @@ class EventSeries extends EditorialContentEntityBase implements EventInterface {
       ->setSetting('datetime_type', 'date')
       ->setDisplayOptions('form', [
         'type' => 'daterange_default',
-        'label' => 'above',
-        'weight' => 6,
+        'weight' => 9,
         'settings' => [
           'format_type' => 'html_date',
           'datetime_type' => 'date',
@@ -503,7 +503,7 @@ class EventSeries extends EditorialContentEntityBase implements EventInterface {
       ->setDisplayOptions('view', [
         'type' => 'recurring_events_eventinstance_date',
         'label' => 'above',
-        'weight' => 10,
+        'weight' => 3,
         'settings' => [
           'link' => TRUE,
           'date_format' => 'F jS, Y h:iA',
@@ -533,7 +533,7 @@ class EventSeries extends EditorialContentEntityBase implements EventInterface {
         'settings' => [
           'display_label' => TRUE,
         ],
-        'weight' => 120,
+        'weight' => 12,
       ])
       ->setDisplayConfigurable('form', TRUE);
 
@@ -601,8 +601,11 @@ class EventSeries extends EditorialContentEntityBase implements EventInterface {
    *   The date object for the consecutive start date.
    */
   public function getConsecutiveStartDate() {
-    $user_timezone = new \DateTimeZone(drupal_get_user_timezone());
-    return $this->get('consecutive_recurring_date')->start_date->setTimezone($user_timezone)->setTime(0, 0, 0);
+    $user_timezone = new \DateTimeZone(date_default_timezone_get());
+    if (!empty($this->get('consecutive_recurring_date')->start_date)) {
+      return $this->get('consecutive_recurring_date')->start_date->setTimezone($user_timezone)->setTime(0, 0, 0);
+    }
+    return NULL;
   }
 
   /**
@@ -612,8 +615,11 @@ class EventSeries extends EditorialContentEntityBase implements EventInterface {
    *   The date object for the consecutive end date.
    */
   public function getConsecutiveEndDate() {
-    $user_timezone = new \DateTimeZone(drupal_get_user_timezone());
-    return $this->get('consecutive_recurring_date')->end_date->setTimezone($user_timezone)->setTime(0, 0, 0);
+    $user_timezone = new \DateTimeZone(date_default_timezone_get());
+    if (!empty($this->get('consecutive_recurring_date')->end_date)) {
+      return $this->get('consecutive_recurring_date')->end_date->setTimezone($user_timezone)->setTime(0, 0, 0);
+    }
+    return NULL;
   }
 
   /**
@@ -683,8 +689,11 @@ class EventSeries extends EditorialContentEntityBase implements EventInterface {
    *   The date object for the daily start date.
    */
   public function getDailyStartDate() {
-    $user_timezone = new \DateTimeZone(drupal_get_user_timezone());
-    return $this->get('daily_recurring_date')->start_date->setTimezone($user_timezone)->setTime(0, 0, 0);
+    $user_timezone = new \DateTimeZone(date_default_timezone_get());
+    if (!empty($this->get('daily_recurring_date')->start_date)) {
+      return $this->get('daily_recurring_date')->start_date->setTimezone($user_timezone)->setTime(0, 0, 0);
+    }
+    return NULL;
   }
 
   /**
@@ -694,8 +703,11 @@ class EventSeries extends EditorialContentEntityBase implements EventInterface {
    *   The date object for the daily end date.
    */
   public function getDailyEndDate() {
-    $user_timezone = new \DateTimeZone(drupal_get_user_timezone());
-    return $this->get('daily_recurring_date')->end_date->setTimezone($user_timezone)->setTime(0, 0, 0);
+    $user_timezone = new \DateTimeZone(date_default_timezone_get());
+    if (!empty($this->get('daily_recurring_date')->end_date)) {
+      return $this->get('daily_recurring_date')->end_date->setTimezone($user_timezone)->setTime(0, 0, 0);
+    }
+    return NULL;
   }
 
   /**
@@ -725,8 +737,11 @@ class EventSeries extends EditorialContentEntityBase implements EventInterface {
    *   The date object for the weekly start date.
    */
   public function getWeeklyStartDate() {
-    $user_timezone = new \DateTimeZone(drupal_get_user_timezone());
-    return $this->get('weekly_recurring_date')->start_date->setTimezone($user_timezone)->setTime(0, 0, 0);
+    $user_timezone = new \DateTimeZone(date_default_timezone_get());
+    if (!empty($this->get('weekly_recurring_date')->start_date)) {
+      return $this->get('weekly_recurring_date')->start_date->setTimezone($user_timezone)->setTime(0, 0, 0);
+    }
+    return NULL;
   }
 
   /**
@@ -736,8 +751,11 @@ class EventSeries extends EditorialContentEntityBase implements EventInterface {
    *   The date object for the weekly end date.
    */
   public function getWeeklyEndDate() {
-    $user_timezone = new \DateTimeZone(drupal_get_user_timezone());
-    return $this->get('weekly_recurring_date')->end_date->setTimezone($user_timezone)->setTime(0, 0, 0);
+    $user_timezone = new \DateTimeZone(date_default_timezone_get());
+    if (!empty($this->get('weekly_recurring_date')->end_date)) {
+      return $this->get('weekly_recurring_date')->end_date->setTimezone($user_timezone)->setTime(0, 0, 0);
+    }
+    return NULL;
   }
 
   /**
@@ -815,8 +833,11 @@ class EventSeries extends EditorialContentEntityBase implements EventInterface {
    *   The date object for the monthly start date.
    */
   public function getMonthlyStartDate() {
-    $user_timezone = new \DateTimeZone(drupal_get_user_timezone());
-    return $this->get('monthly_recurring_date')->start_date->setTimezone($user_timezone)->setTime(0, 0, 0);
+    $user_timezone = new \DateTimeZone(date_default_timezone_get());
+    if (!empty($this->get('monthly_recurring_date')->start_date)) {
+      return $this->get('monthly_recurring_date')->start_date->setTimezone($user_timezone)->setTime(0, 0, 0);
+    }
+    return NULL;
   }
 
   /**
@@ -826,8 +847,11 @@ class EventSeries extends EditorialContentEntityBase implements EventInterface {
    *   The date object for the monthly end date.
    */
   public function getMonthlyEndDate() {
-    $user_timezone = new \DateTimeZone(drupal_get_user_timezone());
-    return $this->get('monthly_recurring_date')->end_date->setTimezone($user_timezone)->setTime(0, 0, 0);
+    $user_timezone = new \DateTimeZone(date_default_timezone_get());
+    if (!empty($this->get('monthly_recurring_date')->end_date)) {
+      return $this->get('monthly_recurring_date')->end_date->setTimezone($user_timezone)->setTime(0, 0, 0);
+    }
+    return NULL;
   }
 
   /**
diff --git a/src/Entity/EventSeriesType.php b/src/Entity/EventSeriesType.php
new file mode 100644
index 0000000000000000000000000000000000000000..e64f948a74ad5687063b0561325a6b5beafe43d8
--- /dev/null
+++ b/src/Entity/EventSeriesType.php
@@ -0,0 +1,84 @@
+<?php
+
+namespace Drupal\recurring_events\Entity;
+
+use Drupal\Core\Config\Entity\ConfigEntityBundleBase;
+
+/**
+ * Defines the Event series type entity.
+ *
+ * @ConfigEntityType(
+ *   id = "eventseries_type",
+ *   label = @Translation("Event series type"),
+ *   handlers = {
+ *     "view_builder" = "Drupal\Core\Entity\EntityViewBuilder",
+ *     "list_builder" = "Drupal\recurring_events\EventSeriesTypeListBuilder",
+ *     "form" = {
+ *       "add" = "Drupal\recurring_events\Form\EventSeriesTypeForm",
+ *       "edit" = "Drupal\recurring_events\Form\EventSeriesTypeForm",
+ *       "delete" = "Drupal\recurring_events\Form\EventSeriesTypeDeleteForm"
+ *     },
+ *     "route_provider" = {
+ *       "html" = "Drupal\recurring_events\EventSeriesTypeHtmlRouteProvider",
+ *     },
+ *   },
+ *   config_prefix = "eventseries_type",
+ *   bundle_of = "eventseries",
+ *   admin_permission = "administer eventseries entity",
+ *   entity_keys = {
+ *     "id" = "id",
+ *     "label" = "label",
+ *     "uuid" = "uuid"
+ *   },
+ *   links = {
+ *     "delete-form" = "/admin/structure/events/series/types/eventseries_type/{eventseries_type}/delete",
+ *     "edit-form" = "/admin/structure/events/series/types/eventseries_type/{eventseries_type}/edit",
+ *     "canonical" = "/admin/structure/events/series/types/eventseries_type/{eventseries_type}",
+ *     "add-form" = "/admin/structure/events/series/types/eventseries_type/add",
+ *     "collection" = "/admin/structure/events/series/types/eventseries_type"
+ *   },
+ *   config_export = {
+ *     "label",
+ *     "id",
+ *     "description",
+ *   }
+ * )
+ */
+class EventSeriesType extends ConfigEntityBundleBase implements EventSeriesTypeInterface {
+
+  /**
+   * The Event series type ID.
+   *
+   * @var string
+   */
+  protected $id;
+
+  /**
+   * The Event series type label.
+   *
+   * @var string
+   */
+  protected $label;
+
+  /**
+   * A brief description of this eventseries type.
+   *
+   * @var string
+   */
+  protected $description;
+
+  /**
+   * {@inheritdoc}
+   */
+  public function id() {
+    return $this->id;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getDescription() {
+    return $this->description;
+  }
+
+}
diff --git a/src/Entity/EventSeriesTypeInterface.php b/src/Entity/EventSeriesTypeInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..2777ca56a72d5ef89f2b62cc5d595c18443fc1e6
--- /dev/null
+++ b/src/Entity/EventSeriesTypeInterface.php
@@ -0,0 +1,20 @@
+<?php
+
+namespace Drupal\recurring_events\Entity;
+
+use Drupal\Core\Config\Entity\ConfigEntityInterface;
+
+/**
+ * Provides an interface for defining Event series type entities.
+ */
+interface EventSeriesTypeInterface extends ConfigEntityInterface {
+
+  /**
+   * Gets the description.
+   *
+   * @return string
+   *   The description of this eventseries type.
+   */
+  public function getDescription();
+
+}
diff --git a/src/Entity/FieldInheritance.php b/src/Entity/FieldInheritance.php
deleted file mode 100644
index 6e94ca6ba167f365e95cf4145c30bc95a085e6ac..0000000000000000000000000000000000000000
--- a/src/Entity/FieldInheritance.php
+++ /dev/null
@@ -1,153 +0,0 @@
-<?php
-
-namespace Drupal\recurring_events\Entity;
-
-use Drupal\Core\Config\Entity\ConfigEntityBase;
-
-/**
- * Defines the Field inheritance entity.
- *
- * @ConfigEntityType(
- *   id = "field_inheritance",
- *   label = @Translation("Field inheritance"),
- *   handlers = {
- *     "view_builder" = "Drupal\Core\Entity\EntityViewBuilder",
- *     "list_builder" = "Drupal\recurring_events\FieldInheritanceListBuilder",
- *     "form" = {
- *       "add" = "Drupal\recurring_events\Form\FieldInheritanceForm",
- *       "edit" = "Drupal\recurring_events\Form\FieldInheritanceForm",
- *       "delete" = "Drupal\recurring_events\Form\FieldInheritanceDeleteForm"
- *     },
- *     "route_provider" = {
- *       "html" = "Drupal\recurring_events\FieldInheritanceHtmlRouteProvider",
- *     },
- *   },
- *   config_prefix = "field_inheritance",
- *   admin_permission = "administer site configuration",
- *   entity_keys = {
- *     "id" = "id",
- *     "label" = "label",
- *     "uuid" = "uuid"
- *   },
- *   links = {
- *     "canonical" = "/admin/structure/events/instance/settings/field_inheritance/{field_inheritance}",
- *     "add-form" = "/admin/structure/events/instance/settings/field_inheritance/add",
- *     "edit-form" = "/admin/structure/events/instance/settings/field_inheritance/{field_inheritance}/edit",
- *     "delete-form" = "/admin/structure/events/instance/settings/field_inheritance/{field_inheritance}/delete",
- *     "collection" = "/admin/structure/events/instance/settings/field_inheritance"
- *   },
- *   config_export = {
- *     "id",
- *     "label",
- *     "type",
- *     "sourceField",
- *     "entityField",
- *     "plugin"
- *   }
- * )
- */
-class FieldInheritance extends ConfigEntityBase implements FieldInheritanceInterface {
-
-  /**
-   * The field inheritance ID.
-   *
-   * @var string
-   */
-  protected $id;
-
-  /**
-   * The field inheritance label.
-   *
-   * @var string
-   */
-  protected $label;
-
-  /**
-   * The field inheritance type.
-   *
-   * @var string
-   */
-  protected $type;
-
-  /**
-   * The field inheritance source field.
-   *
-   * @var string
-   */
-  protected $sourceField;
-
-  /**
-   * The field inheritance entity field.
-   *
-   * @var string
-   */
-  protected $entityField;
-
-  /**
-   * The field inheritance plugin.
-   *
-   * @var string
-   */
-  protected $plugin;
-
-  /**
-   * {@inheritdoc}
-   */
-  public function type() {
-    return isset($this->type) ? $this->type : NULL;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function sourceField() {
-    return isset($this->sourceField) ? $this->sourceField : NULL;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function entityField() {
-    return isset($this->entityField) ? $this->entityField : NULL;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function plugin() {
-    return isset($this->plugin) ? $this->plugin : NULL;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function setType($type) {
-    $this->type = $type;
-    return $this;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function setSourceField($source_field) {
-    $this->sourceField = $source_field;
-    return $this;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function setEntityField($entity_field) {
-    $this->entityField = $entity_field;
-    return $this;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function setPlugin($plugin) {
-    $this->plugin = $plugin;
-    return $this;
-  }
-
-}
diff --git a/src/Entity/FieldInheritanceInterface.php b/src/Entity/FieldInheritanceInterface.php
deleted file mode 100644
index 6d15b4365c72535babed869a77f46448ec6f9557..0000000000000000000000000000000000000000
--- a/src/Entity/FieldInheritanceInterface.php
+++ /dev/null
@@ -1,84 +0,0 @@
-<?php
-
-namespace Drupal\recurring_events\Entity;
-
-use Drupal\Core\Config\Entity\ConfigEntityInterface;
-
-/**
- * Provides an interface for defining Field inheritance entities.
- */
-interface FieldInheritanceInterface extends ConfigEntityInterface {
-
-  /**
-   * Get the inheritance type.
-   *
-   * @return string
-   *   The inheritance type.
-   */
-  public function type();
-
-  /**
-   * Get the inheritance source field.
-   *
-   * @return string
-   *   The inheritance source field.
-   */
-  public function sourceField();
-
-  /**
-   * Get the inheritance entity field.
-   *
-   * @return string
-   *   The inheritance entity field.
-   */
-  public function entityField();
-
-  /**
-   * Get the inheritance plugin.
-   *
-   * @return string
-   *   The inheritance plugin.
-   */
-  public function plugin();
-
-  /**
-   * Set the inheritance type.
-   *
-   * @var string $type
-   *   The inheritance type.
-   *
-   * @return $this
-   */
-  public function setType($type);
-
-  /**
-   * Set the inheritance source field.
-   *
-   * @var string $source_field
-   *   The inheritance source field.
-   *
-   * @return $this
-   */
-  public function setSourceField($source_field);
-
-  /**
-   * Set the inheritance entity field.
-   *
-   * @var string $entity_field
-   *   The inheritance entity field.
-   *
-   * @return $this
-   */
-  public function setEntityField($entity_field);
-
-  /**
-   * Set the inheritance plugin.
-   *
-   * @var string $plugin
-   *   The inheritance plugin.
-   *
-   * @return $this
-   */
-  public function setPlugin($plugin);
-
-}
diff --git a/src/EntityReferenceFieldInheritanceFactory.php b/src/EntityReferenceFieldInheritanceFactory.php
deleted file mode 100644
index b335ed8432a42ecb2c3d25b4120abf547fe1707e..0000000000000000000000000000000000000000
--- a/src/EntityReferenceFieldInheritanceFactory.php
+++ /dev/null
@@ -1,80 +0,0 @@
-<?php
-
-namespace Drupal\recurring_events;
-
-use Drupal\Core\Field\EntityReferenceFieldItemList;
-use Drupal\Core\TypedData\ComputedItemListTrait;
-use Drupal\Core\Field\BaseFieldDefinition;
-use Drupal\Core\TypedData\TypedDataInterface;
-
-/**
- * The EntityReferenceFieldInheritanceFactory class.
- *
- * Note: This class exists separately to the FieldInheritanceFactor because
- * when inheriting data from an entity_reference field we end up with type hints
- * failing during calls to EntityReferenceFormatterBase::getEntitiesToView().
- */
-class EntityReferenceFieldInheritanceFactory extends EntityReferenceFieldItemList {
-
-  use ComputedItemListTrait;
-
-  /**
-   * Constructs a TypedData object given its definition and context.
-   *
-   * @param \Drupal\Core\Field\BaseFieldDefinition $definition
-   *   The data definition.
-   * @param string $name
-   *   (optional) The name of the created property, or NULL if it is the root
-   *   of a typed data tree. Defaults to NULL.
-   * @param \Drupal\Core\TypedData\TypedDataInterface $parent
-   *   (optional) The parent object of the data property, or NULL if it is the
-   *   root of a typed data tree. Defaults to NULL.
-   *
-   * @see \Drupal\Core\TypedData\TypedDataManager::create()
-   */
-  public function __construct(BaseFieldDefinition $definition, $name = NULL, TypedDataInterface $parent = NULL) {
-    parent::__construct($definition, $name, $parent);
-
-    if ($this->getSetting('plugin') === NULL) {
-      throw new \InvalidArgumentException("The definition's 'plugin' key has to specify the plugin to use to inherit data.");
-    }
-
-    if ($this->getSetting('method') === NULL) {
-      throw new \InvalidArgumentException("The definition's 'method' key has to specify the method to use to inherit data. Valid options are inherit, prepend, replace, and append.");
-    }
-
-    if ($this->getSetting('source field') === NULL) {
-      throw new \InvalidArgumentException("The definition's 'source field' key has to specify the field from which to inherit data.");
-    }
-  }
-
-  /**
-   * Compute the field property from state.
-   */
-  protected function computeValue() {
-    $entity = $this->getEntity();
-    $manager = $this->getManager();
-    $configuration = $this->getSettings() + ['entity' => $entity];
-    $plugin = $manager->createInstance($this->getSetting('plugin'), $configuration);
-    $values = $plugin->computeValue();
-    if (!empty($values)) {
-      foreach ($values as $key => $value) {
-        $this->list[$key] = $this->createItem($key, $value);
-      }
-    }
-    else {
-      $this->applyDefaultValue();
-    }
-  }
-
-  /**
-   * Returns the FieldInheritancePluginManager plugin manager.
-   *
-   * @return \Drupal\recurring_events\FieldInheritancePluginManager
-   *   The FieldInheritancePluginManager plugin manager.
-   */
-  protected function getManager() {
-    return \Drupal::service('plugin.manager.field_inheritance');
-  }
-
-}
diff --git a/src/EventCreationService.php b/src/EventCreationService.php
index 9a74d6e27bb684a1ccca7e911deae4780995bdcb..66d9b258dabc611aca7dbdf54c04ca403a93e1a2 100644
--- a/src/EventCreationService.php
+++ b/src/EventCreationService.php
@@ -12,12 +12,17 @@ use Drupal\Core\Messenger\Messenger;
 use Drupal\datetime\Plugin\Field\FieldType\DateTimeItemInterface;
 use Drupal\Core\Entity\EntityFieldManager;
 use Drupal\Core\Field\FieldTypePluginManager;
+use Drupal\Core\StringTranslation\StringTranslationTrait;
+use Drupal\Core\Extension\ModuleHandler;
+use Drupal\Core\Entity\EntityTypeManagerInterface;
 
 /**
  * EventCreationService class.
  */
 class EventCreationService {
 
+  use StringTranslationTrait;
+
   /**
    * The translation interface.
    *
@@ -60,6 +65,20 @@ class EventCreationService {
    */
   protected $entityFieldManager;
 
+  /**
+   * The module handler service.
+   *
+   * @var \Drupal\Core\Extension\ModuleHandler
+   */
+  protected $moduleHandler;
+
+  /**
+   * The entity type manager service.
+   *
+   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
+   */
+  protected $entityTypeManager;
+
   /**
    * Class constructor.
    *
@@ -75,14 +94,20 @@ class EventCreationService {
    *   The field type plugin manager.
    * @param \Drupal\Core\Entity\EntityFieldManager $entity_field_manager
    *   The entity field manager.
+   * @param \Drupal\Core\Extension\ModuleHandler $module_handler
+   *   The module handler service.
+   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
+   *   The entity type manager service.
    */
-  public function __construct(TranslationInterface $translation, Connection $database, LoggerChannelFactoryInterface $logger, Messenger $messenger, FieldTypePluginManager $field_type_plugin_manager, EntityFieldManager $entity_field_manager) {
+  public function __construct(TranslationInterface $translation, Connection $database, LoggerChannelFactoryInterface $logger, Messenger $messenger, FieldTypePluginManager $field_type_plugin_manager, EntityFieldManager $entity_field_manager, ModuleHandler $module_handler, EntityTypeManagerInterface $entity_type_manager) {
     $this->translation = $translation;
     $this->database = $database;
     $this->loggerFactory = $logger->get('recurring_events');
     $this->messenger = $messenger;
     $this->fieldTypePluginManager = $field_type_plugin_manager;
     $this->entityFieldManager = $entity_field_manager;
+    $this->moduleHandler = $module_handler;
+    $this->entityTypeManager = $entity_type_manager;
   }
 
   /**
@@ -95,7 +120,9 @@ class EventCreationService {
       $container->get('logger.factory'),
       $container->get('messenger'),
       $container->get('plugin.manager.field.field_type'),
-      $container->get('entity_field.manager')
+      $container->get('entity_field.manager'),
+      $container->get('module_handler'),
+      $container->get('entity_type.manager')
     );
   }
 
@@ -157,7 +184,7 @@ class EventCreationService {
       $config += $field_class::convertEntityConfigToArray($event);
     }
 
-    \Drupal::moduleHandler()->alter('recurring_events_entity_config_array', $config);
+    $this->moduleHandler->alter('recurring_events_entity_config_array', $config);
 
     return $config;
   }
@@ -174,7 +201,7 @@ class EventCreationService {
   public function convertFormConfigToArray(FormStateInterface $form_state) {
     $config = [];
 
-    $user_timezone = new \DateTimeZone(drupal_get_user_timezone());
+    $user_timezone = new \DateTimeZone(date_default_timezone_get());
     $utc_timezone = new \DateTimeZone(DateTimeItemInterface::STORAGE_TIMEZONE);
     $user_input = $form_state->getUserInput();
 
@@ -224,7 +251,7 @@ class EventCreationService {
       $config += $field_class::convertFormConfigToArray($form_state);
     }
 
-    \Drupal::moduleHandler()->alter('recurring_events_form_config_array', $config);
+    $this->moduleHandler->alter('recurring_events_form_config_array', $config);
 
     return $config;
   }
@@ -296,7 +323,7 @@ class EventCreationService {
             }
           }
 
-          foreach ($form_config['custom_dates'] as $dates) {
+          foreach ($form_config['custom_dates'] as $date) {
             if (!empty($date['start_date']) && !empty($date['end_date'])) {
               $overridden_start_ends[] = $date['start_date']->format('Y-m-d h:ia') . ' - ' . $date['end_date']->format('Y-m-d h:ia');
             }
@@ -316,7 +343,7 @@ class EventCreationService {
       }
     }
 
-    \Drupal::moduleHandler()->alter('recurring_events_diff_array', $diff);
+    $this->moduleHandler->alter('recurring_events_diff_array', $diff);
 
     return $diff;
   }
@@ -339,21 +366,21 @@ class EventCreationService {
       $create_instances = $this->checkForOriginalRecurConfigChanges($event, $original);
       if ($create_instances) {
         // Allow other modules to react prior to the deletion of all instances.
-        \Drupal::moduleHandler()->invokeAll('recurring_events_save_pre_instances_deletion', [$event, $original]);
+        $this->moduleHandler->invokeAll('recurring_events_save_pre_instances_deletion', [$event, $original]);
 
         // Find all the instances and delete them.
         $instances = $event->event_instances->referencedEntities();
         if (!empty($instances)) {
-          foreach ($instances as $index => $instance) {
+          foreach ($instances as $instance) {
             // Allow other modules to react prior to deleting a specific
             // instance after a date configuration change.
-            \Drupal::moduleHandler()->invokeAll('recurring_events_save_pre_instance_deletion', [$event, $instance]);
+            $this->moduleHandler->invokeAll('recurring_events_save_pre_instance_deletion', [$event, $instance]);
 
             $instance->delete();
 
             // Allow other modules to react after deleting a specific instance
             // after a date configuration change.
-            \Drupal::moduleHandler()->invokeAll('recurring_events_save_post_instance_deletion', [$event, $instance]);
+            $this->moduleHandler->invokeAll('recurring_events_save_post_instance_deletion', [$event, $instance]);
           }
           $this->messenger->addStatus($this->translation->translate('A total of %count existing event instances were removed', [
             '%count' => count($instances),
@@ -361,7 +388,7 @@ class EventCreationService {
         }
 
         // Allow other modules to react after the deletion of all instances.
-        \Drupal::moduleHandler()->invokeAll('recurring_events_save_post_instances_deletion', [$event, $original]);
+        $this->moduleHandler->invokeAll('recurring_events_save_post_instances_deletion', [$event, $original]);
       }
     }
 
@@ -381,9 +408,6 @@ class EventCreationService {
     $form_data = $this->convertEntityConfigToArray($event);
     $event_instances = [];
 
-    $timezone = new \DateTimeZone(drupal_get_user_timezone());
-    $utc_timezone = new \DateTimeZone(DateTimeItemInterface::STORAGE_TIMEZONE);
-
     if (!empty($form_data['type'])) {
       if ($form_data['type'] === 'custom') {
         if (!empty($form_data['custom_dates'])) {
@@ -398,7 +422,7 @@ class EventCreationService {
 
           // Allow modules to alter the array of event instances before they
           // get created.
-          \Drupal::moduleHandler()->alter('recurring_events_event_instances_pre_create', $events_to_create, $event);
+          $this->moduleHandler->alter('recurring_events_event_instances_pre_create', $events_to_create, $event);
 
           if (!empty($events_to_create)) {
             foreach ($events_to_create as $custom_event) {
@@ -414,7 +438,7 @@ class EventCreationService {
 
         // Allow modules to alter the array of event instances before they
         // get created.
-        \Drupal::moduleHandler()->alter('recurring_events_event_instances_pre_create', $events_to_create, $event);
+        $this->moduleHandler->alter('recurring_events_event_instances_pre_create', $events_to_create, $event);
 
         if (!empty($events_to_create)) {
           foreach ($events_to_create as $event_to_create) {
@@ -451,14 +475,12 @@ class EventCreationService {
         'value' => $start_date->format(DateTimeItemInterface::DATETIME_STORAGE_FORMAT),
         'end_value' => $end_date->format(DateTimeItemInterface::DATETIME_STORAGE_FORMAT),
       ],
+      'type' => $event->getType(),
     ];
 
-    \Drupal::moduleHandler()->alter('recurring_events_event_instance', $data);
-
-    $entity = \Drupal::entityTypeManager()
-      ->getStorage('eventinstance')
-      ->create($data);
+    $this->moduleHandler->alter('recurring_events_event_instance', $data);
 
+    $entity = $this->entityTypeManager->getStorage('eventinstance')->create($data);
     $entity->save();
 
     return $entity;
@@ -532,7 +554,7 @@ class EventCreationService {
     // hook.
     $recur_fields = [];
     $fields = $this->entityFieldManager->getBaseFieldDefinitions('eventseries');
-    foreach ($fields as $field_name => $field) {
+    foreach ($fields as $field) {
       $field_definition = $this->fieldTypePluginManager->getDefinition($field->getType());
       $class = new \ReflectionClass($field_definition['class']);
       if ($class->implementsInterface('\Drupal\recurring_events\RecurringEventsFieldTypeInterface')) {
@@ -540,9 +562,9 @@ class EventCreationService {
       }
     }
 
-    $recur_fields['custom'] = t('Custom Event');
+    $recur_fields['custom'] = $this->t('Custom Event');
     if ($allow_alter) {
-      \Drupal::moduleHandler()->alter('recurring_events_recur_field_types', $recur_fields);
+      $this->moduleHandler->alter('recurring_events_recur_field_types', $recur_fields);
     }
     return $recur_fields;
   }
diff --git a/src/EventInstanceAccessControlHandler.php b/src/EventInstanceAccessControlHandler.php
index 1a2bf5b8679b3f3cb784c7a49b6e1e075258b66d..c1b42ab0c5a4c66a2747e7333dc0878e890437b3 100644
--- a/src/EventInstanceAccessControlHandler.php
+++ b/src/EventInstanceAccessControlHandler.php
@@ -31,13 +31,13 @@ class EventInstanceAccessControlHandler extends EntityAccessControlHandler {
 
       case 'edit':
         if ($account->id() !== $entity->getOwnerId()) {
-          return AccessResult::allowedIfHasPermission($account, 'edit eventinstance entities');
+          return AccessResult::allowedIfHasPermission($account, 'edit eventinstance entity');
         }
         return AccessResult::allowedIfHasPermission($account, 'edit own eventinstance entity');
 
       case 'delete':
         if ($account->id() !== $entity->getOwnerId()) {
-          return AccessResult::allowedIfHasPermission($account, 'delete eventinstance entities');
+          return AccessResult::allowedIfHasPermission($account, 'delete eventinstance entity');
         }
         return AccessResult::allowedIfHasPermission($account, 'delete own eventinstance entity');
 
diff --git a/src/EventInstanceListBuilder.php b/src/EventInstanceListBuilder.php
index 75a47bada34e90cbcd184d0a291ef07c2817c23d..8d75f8fba0465ecebc81e929eb1b876fb8a9ea52 100644
--- a/src/EventInstanceListBuilder.php
+++ b/src/EventInstanceListBuilder.php
@@ -122,7 +122,7 @@ class EventInstanceListBuilder extends EntityListBuilder {
       '#url' => $entity->getEventSeries()->toUrl(),
     ];
     $config = $this->config->get('recurring_events.eventinstance.config');
-    $timezone = new \DateTimeZone(drupal_get_user_timezone());
+    $timezone = new \DateTimeZone(date_default_timezone_get());
     $entity->date->start_date->setTimezone($timezone);
     $row['date'] = $entity->date->start_date->format($config->get('date_format'));
     $row['author']['data'] = [
diff --git a/src/FieldInheritanceHtmlRouteProvider.php b/src/EventInstanceTypeHtmlRouteProvider.php
similarity index 72%
rename from src/FieldInheritanceHtmlRouteProvider.php
rename to src/EventInstanceTypeHtmlRouteProvider.php
index 52dd17146dda740ad59c8a7e8201c5fa69a9b24a..1d42c64ef37188b2c2c4a418a016efd841df3c8a 100644
--- a/src/FieldInheritanceHtmlRouteProvider.php
+++ b/src/EventInstanceTypeHtmlRouteProvider.php
@@ -6,20 +6,18 @@ use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Entity\Routing\AdminHtmlRouteProvider;
 
 /**
- * Provides routes for Field inheritance entities.
+ * Provides routes for Event instance type entities.
  *
  * @see Drupal\Core\Entity\Routing\AdminHtmlRouteProvider
  * @see Drupal\Core\Entity\Routing\DefaultHtmlRouteProvider
  */
-class FieldInheritanceHtmlRouteProvider extends AdminHtmlRouteProvider {
+class EventInstanceTypeHtmlRouteProvider extends AdminHtmlRouteProvider {
 
   /**
    * {@inheritdoc}
    */
   public function getRoutes(EntityTypeInterface $entity_type) {
     $collection = parent::getRoutes($entity_type);
-
-    // Provide your custom entity routes here.
     return $collection;
   }
 
diff --git a/src/EventInstanceTypeListBuilder.php b/src/EventInstanceTypeListBuilder.php
new file mode 100644
index 0000000000000000000000000000000000000000..dfa968cb2b154b7251f5ed57ffa524b3a1d3f297
--- /dev/null
+++ b/src/EventInstanceTypeListBuilder.php
@@ -0,0 +1,45 @@
+<?php
+
+namespace Drupal\recurring_events;
+
+use Drupal\Core\Config\Entity\ConfigEntityListBuilder;
+use Drupal\Core\Entity\EntityInterface;
+
+/**
+ * Provides a listing of Event instance type entities.
+ */
+class EventInstanceTypeListBuilder extends ConfigEntityListBuilder {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function buildHeader() {
+    $header['label'] = $this->t('Event instance type');
+    $header['id'] = $this->t('Machine name');
+    return $header + parent::buildHeader();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getDefaultOperations(EntityInterface $entity) {
+    $operations = parent::getDefaultOperations($entity);
+    // Place the edit operation after the operations added by field_ui.module
+    // which have the weights 15, 20, 25.
+    if (isset($operations['edit'])) {
+      $operations['edit']['weight'] = 30;
+    }
+    return $operations;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function buildRow(EntityInterface $entity) {
+    $row['label'] = $entity->label();
+    $row['id'] = $entity->id();
+    // You probably want a few more properties here...
+    return $row + parent::buildRow($entity);
+  }
+
+}
diff --git a/src/EventInterface.php b/src/EventInterface.php
index 6644e0c5c860aba7c11f6ef6cc5323a182b9a784..73df63b123f3386e6717ef4a162d3e306ac45529 100644
--- a/src/EventInterface.php
+++ b/src/EventInterface.php
@@ -41,29 +41,4 @@ interface EventInterface extends ContentEntityInterface, EntityChangedInterface,
    */
   public function setRevisionCreationTime($timestamp);
 
-  /**
-   * Gets the event revision author.
-   *
-   * @return \Drupal\user\UserInterface
-   *   The user entity for the revision author.
-   *
-   * @deprecated in Drupal 8.2.0, will be removed before Drupal 9.0.0. Use
-   *   \Drupal\Core\Entity\RevisionLogInterface::getRevisionUser() instead.
-   */
-  public function getRevisionAuthor();
-
-  /**
-   * Sets the event revision author.
-   *
-   * @param int $uid
-   *   The user ID of the revision author.
-   *
-   * @return \Drupal\recurring_events\EventInterface
-   *   The called event entity.
-   *
-   * @deprecated in Drupal 8.2.0, will be removed before Drupal 9.0.0. Use
-   *   \Drupal\Core\Entity\RevisionLogInterface::setRevisionUserId() instead.
-   */
-  public function setRevisionAuthorId($uid);
-
 }
diff --git a/src/EventSeriesAccessControlHandler.php b/src/EventSeriesAccessControlHandler.php
index 67d607f947402694f89f462581848d9c104ed3ce..b06f86d4a86f796be2932529a54e5d6189dbeb0f 100644
--- a/src/EventSeriesAccessControlHandler.php
+++ b/src/EventSeriesAccessControlHandler.php
@@ -31,13 +31,13 @@ class EventSeriesAccessControlHandler extends EntityAccessControlHandler {
 
       case 'edit':
         if ($account->id() !== $entity->getOwnerId()) {
-          return AccessResult::allowedIfHasPermission($account, 'edit eventseries entities');
+          return AccessResult::allowedIfHasPermission($account, 'edit eventseries entity');
         }
         return AccessResult::allowedIfHasPermission($account, 'edit own eventseries entity');
 
       case 'delete':
         if ($account->id() !== $entity->getOwnerId()) {
-          return AccessResult::allowedIfHasPermission($account, 'delete eventseries entities');
+          return AccessResult::allowedIfHasPermission($account, 'delete eventseries entity');
         }
         return AccessResult::allowedIfHasPermission($account, 'delete own eventseries entity');
 
diff --git a/src/EventSeriesListBuilder.php b/src/EventSeriesListBuilder.php
index 4aa561fc5b6732cc9b6b6303c3f6447c6c1ce4eb..38ed5f3bf5b0d3d0a8719ba83ccdf7d428bb54ea 100644
--- a/src/EventSeriesListBuilder.php
+++ b/src/EventSeriesListBuilder.php
@@ -125,7 +125,7 @@ class EventSeriesListBuilder extends EntityListBuilder {
     $row['type'] = $entity->recur_type->value;
     $row['instances'] = $entity->getInstanceCount();
     $row['starts'] = $this->t('None');
-    $timezone = new \DateTimeZone(drupal_get_user_timezone());
+    $timezone = new \DateTimeZone(date_default_timezone_get());
     if (!empty($entity->getSeriesStart())) {
       $config = $this->config->get('recurring_events.eventseries.config');
       $start_date = $entity->getSeriesStart();
diff --git a/src/EventSeriesTypeHtmlRouteProvider.php b/src/EventSeriesTypeHtmlRouteProvider.php
new file mode 100644
index 0000000000000000000000000000000000000000..f2cf604d0c54bc00d033e33d0c25747986b5529f
--- /dev/null
+++ b/src/EventSeriesTypeHtmlRouteProvider.php
@@ -0,0 +1,24 @@
+<?php
+
+namespace Drupal\recurring_events;
+
+use Drupal\Core\Entity\EntityTypeInterface;
+use Drupal\Core\Entity\Routing\AdminHtmlRouteProvider;
+
+/**
+ * Provides routes for Event series type entities.
+ *
+ * @see Drupal\Core\Entity\Routing\AdminHtmlRouteProvider
+ * @see Drupal\Core\Entity\Routing\DefaultHtmlRouteProvider
+ */
+class EventSeriesTypeHtmlRouteProvider extends AdminHtmlRouteProvider {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getRoutes(EntityTypeInterface $entity_type) {
+    $collection = parent::getRoutes($entity_type);
+    return $collection;
+  }
+
+}
diff --git a/src/EventSeriesTypeListBuilder.php b/src/EventSeriesTypeListBuilder.php
new file mode 100644
index 0000000000000000000000000000000000000000..82d44493384dd5ccce5178987723237c7c63054c
--- /dev/null
+++ b/src/EventSeriesTypeListBuilder.php
@@ -0,0 +1,45 @@
+<?php
+
+namespace Drupal\recurring_events;
+
+use Drupal\Core\Config\Entity\ConfigEntityListBuilder;
+use Drupal\Core\Entity\EntityInterface;
+
+/**
+ * Provides a listing of Event series type entities.
+ */
+class EventSeriesTypeListBuilder extends ConfigEntityListBuilder {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function buildHeader() {
+    $header['label'] = $this->t('Event series type');
+    $header['id'] = $this->t('Machine name');
+    return $header + parent::buildHeader();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getDefaultOperations(EntityInterface $entity) {
+    $operations = parent::getDefaultOperations($entity);
+    // Place the edit operation after the operations added by field_ui.module
+    // which have the weights 15, 20, 25.
+    if (isset($operations['edit'])) {
+      $operations['edit']['weight'] = 30;
+    }
+    return $operations;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function buildRow(EntityInterface $entity) {
+    $row['label'] = $entity->label();
+    $row['id'] = $entity->id();
+    // You probably want a few more properties here...
+    return $row + parent::buildRow($entity);
+  }
+
+}
diff --git a/src/ExcludedDatesHtmlRouteProvider.php b/src/ExcludedDatesHtmlRouteProvider.php
index edc38c0c08abe5b694d86f1e1b0e5d0f5d59227e..2699611302237721fd141a891e4e518f8655bf2a 100644
--- a/src/ExcludedDatesHtmlRouteProvider.php
+++ b/src/ExcludedDatesHtmlRouteProvider.php
@@ -4,7 +4,6 @@ namespace Drupal\recurring_events;
 
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Entity\Routing\AdminHtmlRouteProvider;
-use Symfony\Component\Routing\Route;
 
 /**
  * Provides routes for Excluded dates entities.
@@ -19,9 +18,6 @@ class ExcludedDatesHtmlRouteProvider extends AdminHtmlRouteProvider {
    */
   public function getRoutes(EntityTypeInterface $entity_type) {
     $collection = parent::getRoutes($entity_type);
-
-    // Provide your custom entity routes here.
-
     return $collection;
   }
 
diff --git a/src/FieldInheritanceFactory.php b/src/FieldInheritanceFactory.php
deleted file mode 100644
index c34be3a38b0baa6911ddbd4e13b3388ba265f884..0000000000000000000000000000000000000000
--- a/src/FieldInheritanceFactory.php
+++ /dev/null
@@ -1,76 +0,0 @@
-<?php
-
-namespace Drupal\recurring_events;
-
-use Drupal\Core\Field\FieldItemList;
-use Drupal\Core\TypedData\ComputedItemListTrait;
-use Drupal\Core\Field\BaseFieldDefinition;
-use Drupal\Core\TypedData\TypedDataInterface;
-
-/**
- * The FieldInheritanceFactory class.
- */
-class FieldInheritanceFactory extends FieldItemList {
-
-  use ComputedItemListTrait;
-
-  /**
-   * Constructs a FieldInheritanceFactory object.
-   *
-   * @param \Drupal\Core\Field\BaseFieldDefinition $definition
-   *   The data definition.
-   * @param string $name
-   *   (optional) The name of the created property, or NULL if it is the root
-   *   of a typed data tree. Defaults to NULL.
-   * @param \Drupal\Core\TypedData\TypedDataInterface $parent
-   *   (optional) The parent object of the data property, or NULL if it is the
-   *   root of a typed data tree. Defaults to NULL.
-   *
-   * @see \Drupal\Core\TypedData\TypedDataManager::create()
-   */
-  public function __construct(BaseFieldDefinition $definition, $name = NULL, TypedDataInterface $parent = NULL) {
-    parent::__construct($definition, $name, $parent);
-
-    if ($this->getSetting('plugin') === NULL) {
-      throw new \InvalidArgumentException("The definition's 'plugin' key has to specify the plugin to use to inherit data.");
-    }
-
-    if ($this->getSetting('method') === NULL) {
-      throw new \InvalidArgumentException("The definition's 'method' key has to specify the method to use to inherit data. Valid options are inherit, prepend, replace, and append.");
-    }
-
-    if ($this->getSetting('source field') === NULL) {
-      throw new \InvalidArgumentException("The definition's 'source field' key has to specify the field from which to inherit data.");
-    }
-  }
-
-  /**
-   * Compute the field property from state.
-   */
-  protected function computeValue() {
-    $entity = $this->getEntity();
-    $manager = $this->getManager();
-    $configuration = $this->getSettings() + ['entity' => $entity];
-    $plugin = $manager->createInstance($this->getSetting('plugin'), $configuration);
-    $values = $plugin->computeValue();
-    if (!empty($values)) {
-      foreach ($values as $key => $value) {
-        $this->list[$key] = $this->createItem($key, $value);
-      }
-    }
-    else {
-      $this->applyDefaultValue();
-    }
-  }
-
-  /**
-   * Returns the FieldInheritancePluginManager plugin manager.
-   *
-   * @return \Drupal\recurring_events\FieldInheritancePluginManager
-   *   The FieldInheritancePluginManager plugin manager.
-   */
-  protected function getManager() {
-    return \Drupal::service('plugin.manager.field_inheritance');
-  }
-
-}
diff --git a/src/FieldInheritanceListBuilder.php b/src/FieldInheritanceListBuilder.php
deleted file mode 100644
index e2e029bca4293ff0d3d1aa5405f7801176f82e80..0000000000000000000000000000000000000000
--- a/src/FieldInheritanceListBuilder.php
+++ /dev/null
@@ -1,37 +0,0 @@
-<?php
-
-namespace Drupal\recurring_events;
-
-use Drupal\Core\Config\Entity\ConfigEntityListBuilder;
-use Drupal\Core\Entity\EntityInterface;
-
-/**
- * Provides a listing of Field inheritance entities.
- */
-class FieldInheritanceListBuilder extends ConfigEntityListBuilder {
-
-  /**
-   * {@inheritdoc}
-   */
-  public function buildHeader() {
-    $header['label'] = $this->t('Field inheritance');
-    $header['id'] = $this->t('Machine name');
-    $header['type'] = $this->t('Type');
-    $header['source_field'] = $this->t('Source Field');
-    $header['entity_field'] = $this->t('Entity Field');
-    return $header + parent::buildHeader();
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function buildRow(EntityInterface $entity) {
-    $row['label'] = $entity->label();
-    $row['id'] = $entity->id();
-    $row['type'] = $entity->type();
-    $row['source_field'] = $entity->sourceField();
-    $row['entity_field'] = $entity->entityField() ?: $this->t('N/A');
-    return $row + parent::buildRow($entity);
-  }
-
-}
diff --git a/src/FieldInheritancePluginInterface.php b/src/FieldInheritancePluginInterface.php
deleted file mode 100644
index 278a1ec4db54e06a98b14e4c85229a7450e042a1..0000000000000000000000000000000000000000
--- a/src/FieldInheritancePluginInterface.php
+++ /dev/null
@@ -1,15 +0,0 @@
-<?php
-
-namespace Drupal\recurring_events;
-
-/**
- * FieldInheritancePluginInterface interface definition.
- */
-interface FieldInheritancePluginInterface {
-
-  /**
-   * Compute the value of the field.
-   */
-  public function computeValue();
-
-}
diff --git a/src/FieldInheritancePluginManager.php b/src/FieldInheritancePluginManager.php
deleted file mode 100644
index 6ab747982a15a777d13db59530e0f029c53602d3..0000000000000000000000000000000000000000
--- a/src/FieldInheritancePluginManager.php
+++ /dev/null
@@ -1,41 +0,0 @@
-<?php
-
-namespace Drupal\recurring_events;
-
-use Drupal\Core\Cache\CacheBackendInterface;
-use Drupal\Core\Extension\ModuleHandlerInterface;
-use Drupal\Core\Plugin\DefaultPluginManager;
-
-/**
- * Provides a FieldInheritance plugin manager.
- *
- * @see \Drupal\recurring_events\Annotation\FieldInheritance
- * @see \Drupal\recurring_events\FieldInheritancePluginInterface
- * @see plugin_api
- */
-class FieldInheritancePluginManager extends DefaultPluginManager {
-
-  /**
-   * Constructs a FieldInheritancePluginManager object.
-   *
-   * @param \Traversable $namespaces
-   *   An object that implements \Traversable which contains the root paths
-   *   keyed by the corresponding namespace to look for plugin implementations.
-   * @param \Drupal\Core\Cache\CacheBackendInterface $cache_backend
-   *   Cache backend instance to use.
-   * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
-   *   The module handler to invoke the alter hook with.
-   */
-  public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler) {
-    parent::__construct(
-      'Plugin/FieldInheritance',
-      $namespaces,
-      $module_handler,
-      'Drupal\recurring_events\FieldInheritancePluginInterface',
-      'Drupal\recurring_events\Annotation\FieldInheritance'
-    );
-    $this->alterInfo('field_inheritance_info');
-    $this->setCacheBackend($cache_backend, 'field_inheritance_info_plugins');
-  }
-
-}
diff --git a/src/Form/EventInstanceDeleteForm.php b/src/Form/EventInstanceDeleteForm.php
index 33854d614a089d566593b99192492eaa69d49617..20d500f49bb409d990088f188f9749d3f7640331 100644
--- a/src/Form/EventInstanceDeleteForm.php
+++ b/src/Form/EventInstanceDeleteForm.php
@@ -5,7 +5,7 @@ namespace Drupal\recurring_events\Form;
 use Drupal\Core\Entity\ContentEntityDeleteForm;
 use Drupal\Core\Form\FormStateInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
-use Drupal\Core\Entity\EntityManagerInterface;
+use Drupal\Core\Entity\EntityRepositoryInterface;
 use Drupal\Core\Url;
 use Drupal\Core\Messenger\Messenger;
 use Drupal\Core\Datetime\DateFormatter;
@@ -41,15 +41,15 @@ class EventInstanceDeleteForm extends ContentEntityDeleteForm {
   /**
    * Construct a EventInstanceDeleteForm.
    *
-   * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
-   *   The entity manager service.
+   * @param \Drupal\Core\Entity\EntityRepositoryInterface $entity_repository
+   *   The entity repository service.
    * @param \Drupal\Core\Messenger\Messenger $messenger
    *   The messenger service.
    * @param \Drupal\Core\Datetime\DateFormatter $date_formatter
    *   The date formatter service.
    */
-  public function __construct(EntityManagerInterface $entity_manager, Messenger $messenger, DateFormatter $date_formatter) {
-    parent::__construct($entity_manager);
+  public function __construct(EntityRepositoryInterface $entity_repository, Messenger $messenger, DateFormatter $date_formatter) {
+    parent::__construct($entity_repository);
     $this->messenger = $messenger;
     $this->dateFormatter = $date_formatter;
   }
@@ -59,7 +59,7 @@ class EventInstanceDeleteForm extends ContentEntityDeleteForm {
    */
   public static function create(ContainerInterface $container) {
     return new static(
-      $container->get('entity.manager'),
+      $container->get('entity.repository'),
       $container->get('messenger'),
       $container->get('date.formatter')
     );
@@ -75,7 +75,7 @@ class EventInstanceDeleteForm extends ContentEntityDeleteForm {
       return $this
         ->t('Are you sure you want to delete the @language translation of the @entity-type %label?', [
           '@language' => $entity->language()->getName(),
-          '@entity-type' => $this->getEntity()->getEntityType()->getLowercaseLabel(),
+          '@entity-type' => $this->getEntity()->getEntityType()->getSingularLabel(),
           '%label' => $this->entity->getEventSeries()->title->value,
         ]);
     }
diff --git a/src/Form/EventInstanceForm.php b/src/Form/EventInstanceForm.php
index 4be8c39fb92f6bbef5a98a24fa0ce12ef89d15a5..f084247ccc63d4173a91e878eb3aa13732960a48 100644
--- a/src/Form/EventInstanceForm.php
+++ b/src/Form/EventInstanceForm.php
@@ -5,8 +5,10 @@ namespace Drupal\recurring_events\Form;
 use Drupal\Core\Entity\ContentEntityForm;
 use Drupal\Core\Form\FormStateInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
-use Drupal\Core\Entity\EntityManagerInterface;
+use Drupal\Core\Entity\EntityRepositoryInterface;
 use Drupal\Core\Messenger\Messenger;
+use Drupal\Core\Session\AccountProxyInterface;
+use Drupal\Component\Datetime\TimeInterface;
 
 /**
  * Form controller for the eventinstance entity edit forms.
@@ -22,27 +24,49 @@ class EventInstanceForm extends ContentEntityForm {
    */
   protected $messenger;
 
+  /**
+   * The current user.
+   *
+   * @var \Drupal\Core\Session\AccountProxyInterface
+   */
+  protected $currentUser;
+
+  /**
+   * The time service.
+   *
+   * @var \Drupal\Component\Datetime\TimeInterface
+   */
+  protected $time;
+
   /**
    * {@inheritdoc}
    */
   public static function create(ContainerInterface $container) {
     return new static(
-      $container->get('entity.manager'),
-      $container->get('messenger')
+      $container->get('entity.repository'),
+      $container->get('messenger'),
+      $container->get('current_user'),
+      $container->get('datetime.time')
     );
   }
 
   /**
    * Construct an EventInstanceForm.
    *
-   * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
-   *   The entity manager service.
+   * @param \Drupal\Core\Entity\EntityRepositoryInterface $entity_repository
+   *   The entity repository service.
    * @param \Drupal\Core\Messenger\Messenger $messenger
    *   The messenger service.
+   * @param \Drupal\Core\Session\AccountProxyInterface $current_user
+   *   The current user.
+   * @param \Drupal\Component\Datetime\TimeInterface $time
+   *   The time service.
    */
-  public function __construct(EntityManagerInterface $entity_manager, Messenger $messenger) {
+  public function __construct(EntityRepositoryInterface $entity_repository, Messenger $messenger, AccountProxyInterface $current_user, TimeInterface $time) {
     $this->messenger = $messenger;
-    parent::__construct($entity_manager);
+    $this->currentUser = $current_user;
+    $this->time = $time;
+    parent::__construct($entity_repository);
   }
 
   /**
@@ -96,8 +120,8 @@ class EventInstanceForm extends ContentEntityForm {
       $entity->setNewRevision();
 
       // If a new revision is created, save the current user as revision author.
-      $entity->setRevisionCreationTime(REQUEST_TIME);
-      $entity->setRevisionUserId(\Drupal::currentUser()->id());
+      $entity->setRevisionCreationTime($this->time->getRequestTime());
+      $entity->setRevisionUserId($this->currentUser->id());
     }
     else {
       $entity->setNewRevision(FALSE);
@@ -106,12 +130,12 @@ class EventInstanceForm extends ContentEntityForm {
     parent::save($form, $form_state);
 
     if ($entity->isDefaultTranslation()) {
-      $message = t('Event instance of %label has been saved.', [
+      $message = $this->t('Event instance of %label has been saved.', [
         '%label' => $entity->getEventSeries()->title->value,
       ]);
     }
     else {
-      $message = t('@language translation of the Event Instance %label has been saved.', [
+      $message = $this->t('@language translation of the Event Instance %label has been saved.', [
         '@language' => $entity->language()->getName(),
         '%label' => $entity->getUntranslated()->getEventSeries()->title->value,
       ]);
diff --git a/src/Form/EventInstanceRevisionDeleteForm.php b/src/Form/EventInstanceRevisionDeleteForm.php
index b67b92ad2cafba73102aa18edd441b78095d4796..4fcb048f4175b068886b1725675b8ca3c7f9394c 100644
--- a/src/Form/EventInstanceRevisionDeleteForm.php
+++ b/src/Form/EventInstanceRevisionDeleteForm.php
@@ -10,6 +10,7 @@ use Drupal\Core\Url;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Drupal\Core\Datetime\DateFormatterInterface;
 use Drupal\Core\Messenger\Messenger;
+use Drupal\Core\StringTranslation\StringTranslationTrait;
 
 /**
  * Provides a form for deleting a eventinstance revision.
@@ -18,6 +19,8 @@ use Drupal\Core\Messenger\Messenger;
  */
 class EventInstanceRevisionDeleteForm extends ConfirmFormBase {
 
+  use StringTranslationTrait;
+
   /**
    * The eventinstance revision.
    *
@@ -96,7 +99,7 @@ class EventInstanceRevisionDeleteForm extends ConfirmFormBase {
    * {@inheritdoc}
    */
   public function getQuestion() {
-    return t('Are you sure you want to delete the revision from %revision-date?', [
+    return $this->t('Are you sure you want to delete the revision from %revision-date?', [
       '%revision-date' => $this->dateFormatter->format($this->revision->getRevisionCreationTime()),
     ]);
   }
@@ -112,7 +115,7 @@ class EventInstanceRevisionDeleteForm extends ConfirmFormBase {
    * {@inheritdoc}
    */
   public function getConfirmText() {
-    return t('Delete');
+    return $this->t('Delete');
   }
 
   /**
@@ -132,7 +135,7 @@ class EventInstanceRevisionDeleteForm extends ConfirmFormBase {
     $this->eventInstanceStorage->deleteRevision($this->revision->getRevisionId());
 
     $this->logger('content')->notice('eventinstance: deleted %title revision %revision.', ['%title' => $this->revision->label(), '%revision' => $this->revision->getRevisionId()]);
-    $this->messenger->addMessage(t('Revision from %revision-date of eventinstance %title has been deleted.', [
+    $this->messenger->addMessage($this->t('Revision from %revision-date of eventinstance %title has been deleted.', [
       '%revision-date' => $this->dateFormatter->format($this->revision->getRevisionCreationTime()),
       '%title' => $this->revision->label(),
     ]));
diff --git a/src/Form/EventInstanceRevisionRevertForm.php b/src/Form/EventInstanceRevisionRevertForm.php
index 1122e360a28911716ddcf8dd0b784e15e41d5d10..53a65df94b3bff1f26986a9a56d8022c1983e887 100644
--- a/src/Form/EventInstanceRevisionRevertForm.php
+++ b/src/Form/EventInstanceRevisionRevertForm.php
@@ -10,6 +10,7 @@ use Drupal\Core\Url;
 use Drupal\recurring_events\EventInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Drupal\Core\Messenger\Messenger;
+use Drupal\Core\StringTranslation\StringTranslationTrait;
 
 /**
  * Provides a form for reverting an eventinstance revision.
@@ -18,6 +19,8 @@ use Drupal\Core\Messenger\Messenger;
  */
 class EventInstanceRevisionRevertForm extends ConfirmFormBase {
 
+  use StringTranslationTrait;
+
   /**
    * The eventinstance revision.
    *
@@ -84,7 +87,7 @@ class EventInstanceRevisionRevertForm extends ConfirmFormBase {
    * {@inheritdoc}
    */
   public function getQuestion() {
-    return t('Are you sure you want to revert to the revision from %revision-date?', ['%revision-date' => $this->dateFormatter->format($this->revision->getRevisionCreationTime())]);
+    return $this->t('Are you sure you want to revert to the revision from %revision-date?', ['%revision-date' => $this->dateFormatter->format($this->revision->getRevisionCreationTime())]);
   }
 
   /**
@@ -98,7 +101,7 @@ class EventInstanceRevisionRevertForm extends ConfirmFormBase {
    * {@inheritdoc}
    */
   public function getConfirmText() {
-    return t('Revert');
+    return $this->t('Revert');
   }
 
   /**
@@ -127,11 +130,11 @@ class EventInstanceRevisionRevertForm extends ConfirmFormBase {
     $original_revision_timestamp = $this->revision->getRevisionCreationTime();
 
     $this->revision = $this->prepareRevertedRevision($this->revision, $form_state);
-    $this->revision->revision_log = t('Copy of the revision from %date.', ['%date' => $this->dateFormatter->format($original_revision_timestamp)]);
+    $this->revision->revision_log = $this->t('Copy of the revision from %date.', ['%date' => $this->dateFormatter->format($original_revision_timestamp)]);
     $this->revision->save();
 
     $this->logger('content')->notice('eventinstance: reverted %title revision %revision.', ['%title' => $this->revision->label(), '%revision' => $this->revision->getRevisionId()]);
-    $this->messenger->addMessage(t('eventinstance %title has been reverted to the revision from %revision-date.', [
+    $this->messenger->addMessage($this->t('eventinstance %title has been reverted to the revision from %revision-date.', [
       '%title' => $this->revision->label(),
       '%revision-date' => $this->dateFormatter->format($original_revision_timestamp),
     ]));
@@ -155,7 +158,7 @@ class EventInstanceRevisionRevertForm extends ConfirmFormBase {
   protected function prepareRevertedRevision(EventInterface $revision, FormStateInterface $form_state) {
     $revision->setNewRevision();
     $revision->isDefaultRevision(TRUE);
-    $revision->setRevisionCreationTime(REQUEST_TIME);
+    $revision->setRevisionCreationTime(\Drupal::time()->getRequestTime());
 
     return $revision;
   }
diff --git a/src/Form/EventInstanceRevisionRevertTranslationForm.php b/src/Form/EventInstanceRevisionRevertTranslationForm.php
index 1bb8be93060ad4450db88e54427badb657be1f74..10f02f6e37af89d86f866867609df1bd3f622d8f 100644
--- a/src/Form/EventInstanceRevisionRevertTranslationForm.php
+++ b/src/Form/EventInstanceRevisionRevertTranslationForm.php
@@ -8,6 +8,7 @@ use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Language\LanguageManagerInterface;
 use Drupal\recurring_events\EventInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
+use Drupal\Core\StringTranslation\StringTranslationTrait;
 
 /**
  * Provides form to revert an eventinstance revision for a single translation.
@@ -16,6 +17,8 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
  */
 class EventInstanceRevisionRevertTranslationForm extends EventInstanceRevisionRevertForm {
 
+  use StringTranslationTrait;
+
   /**
    * The language to be reverted.
    *
@@ -67,7 +70,7 @@ class EventInstanceRevisionRevertTranslationForm extends EventInstanceRevisionRe
    * {@inheritdoc}
    */
   public function getQuestion() {
-    return t('Are you sure you want to revert @language translation to the revision from %revision-date?', ['@language' => $this->languageManager->getLanguageName($this->langcode), '%revision-date' => $this->dateFormatter->format($this->revision->getRevisionCreationTime())]);
+    return $this->t('Are you sure you want to revert @language translation to the revision from %revision-date?', ['@language' => $this->languageManager->getLanguageName($this->langcode), '%revision-date' => $this->dateFormatter->format($this->revision->getRevisionCreationTime())]);
   }
 
   /**
@@ -106,7 +109,7 @@ class EventInstanceRevisionRevertTranslationForm extends EventInstanceRevisionRe
 
     $latest_revision_translation->setNewRevision();
     $latest_revision_translation->isDefaultRevision(TRUE);
-    $revision->setRevisionCreationTime(REQUEST_TIME);
+    $revision->setRevisionCreationTime(\Drupal::time()->getRequestTime());
 
     return $latest_revision_translation;
   }
diff --git a/src/Form/EventInstanceSettingsForm.php b/src/Form/EventInstanceSettingsForm.php
index b4572ca3c9a1b5a400abc3f6c4aa42d437b738da..db8c0ae934c6f358c9b446dce7514841bb969047 100644
--- a/src/Form/EventInstanceSettingsForm.php
+++ b/src/Form/EventInstanceSettingsForm.php
@@ -60,7 +60,7 @@ class EventInstanceSettingsForm extends ConfigFormBase {
    *   Form definition array.
    */
   public function buildForm(array $form, FormStateInterface $form_state) {
-    $config = $this->config('recurring_events.eventseries.config');
+    $config = $this->config('recurring_events.eventinstance.config');
 
     $php_date_url = Url::fromUri('https://secure.php.net/manual/en/function.date.php');
     $php_date_link = Link::fromTextAndUrl($this->t('PHP date/time format'), $php_date_url);
diff --git a/src/Form/EventInstanceTypeForm.php b/src/Form/EventInstanceTypeForm.php
new file mode 100644
index 0000000000000000000000000000000000000000..0c9d369df868a0d615b6f6cea73b026e29cab692
--- /dev/null
+++ b/src/Form/EventInstanceTypeForm.php
@@ -0,0 +1,97 @@
+<?php
+
+namespace Drupal\recurring_events\Form;
+
+use Drupal\Core\Entity\EntityForm;
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Messenger\Messenger;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * Class EventInstanceTypeForm.
+ */
+class EventInstanceTypeForm extends EntityForm {
+
+  /**
+   * The messenger service.
+   *
+   * @var \Drupal\Core\Messenger\Messenger
+   */
+  protected $messenger;
+
+  /**
+   * Constructs a new EventSeriesTypeForm.
+   *
+   * @param \Drupal\Core\Messenger\Messenger $messenger
+   *   The messenger service.
+   */
+  public function __construct(Messenger $messenger) {
+    $this->messenger = $messenger;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container) {
+    return new static(
+      $container->get('messenger')
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function form(array $form, FormStateInterface $form_state) {
+    $form = parent::form($form, $form_state);
+
+    $eventinstance_type = $this->entity;
+    $form['label'] = [
+      '#type' => 'textfield',
+      '#title' => $this->t('Label'),
+      '#maxlength' => 255,
+      '#default_value' => $eventinstance_type->label(),
+      '#description' => $this->t("Label for the Event instance type."),
+      '#required' => TRUE,
+    ];
+
+    $form['id'] = [
+      '#type' => 'machine_name',
+      '#default_value' => $eventinstance_type->id(),
+      '#machine_name' => [
+        'exists' => '\Drupal\recurring_events\Entity\EventInstanceType::load',
+      ],
+      '#disabled' => !$eventinstance_type->isNew(),
+    ];
+
+    $form['description'] = [
+      '#title' => $this->t('Description'),
+      '#type' => 'textarea',
+      '#default_value' => $eventinstance_type->getDescription(),
+    ];
+
+    return $form;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function save(array $form, FormStateInterface $form_state) {
+    $eventinstance_type = $this->entity;
+    $status = $eventinstance_type->save();
+
+    switch ($status) {
+      case SAVED_NEW:
+        $this->messenger->addMessage($this->t('Created the %label event instance type.', [
+          '%label' => $eventinstance_type->label(),
+        ]));
+        break;
+
+      default:
+        $this->messenger->addMessage($this->t('Saved the %label event instance type.', [
+          '%label' => $eventinstance_type->label(),
+        ]));
+    }
+    $form_state->setRedirectUrl($eventinstance_type->toUrl('collection'));
+  }
+
+}
diff --git a/src/Form/EventSeriesDeleteForm.php b/src/Form/EventSeriesDeleteForm.php
index 131250baf9671822f1285e177107b0cd9077de0e..46d7ca4f216b9d1a29693b5b1dab644507b658d2 100644
--- a/src/Form/EventSeriesDeleteForm.php
+++ b/src/Form/EventSeriesDeleteForm.php
@@ -5,7 +5,7 @@ namespace Drupal\recurring_events\Form;
 use Drupal\Core\Entity\ContentEntityDeleteForm;
 use Drupal\Core\Form\FormStateInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
-use Drupal\Core\Entity\EntityManagerInterface;
+use Drupal\Core\Entity\EntityRepositoryInterface;
 use Drupal\Core\Url;
 use Drupal\Core\Config\ConfigFactory;
 use Drupal\Core\Messenger\Messenger;
@@ -44,13 +44,14 @@ class EventSeriesDeleteForm extends ContentEntityDeleteForm {
    *
    * @var \Drupal\Core\Render\Renderer
    */
+  protected $renderer;
 
   /**
    * {@inheritdoc}
    */
   public static function create(ContainerInterface $container) {
     return new static(
-      $container->get('entity.manager'),
+      $container->get('entity.repository'),
       $container->get('messenger'),
       $container->get('renderer'),
       $container->get('config.factory')
@@ -60,8 +61,8 @@ class EventSeriesDeleteForm extends ContentEntityDeleteForm {
   /**
    * Construct an EventSeriesDeleteForm.
    *
-   * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
-   *   The entity manager service.
+   * @param \Drupal\Core\Entity\EntityRepositoryInterface $entity_repository
+   *   The entity repository service.
    * @param \Drupal\Core\Messenger\Messenger $messenger
    *   The messenger service.
    * @param \Drupal\Core\Render\Renderer $renderer
@@ -69,11 +70,11 @@ class EventSeriesDeleteForm extends ContentEntityDeleteForm {
    * @param \Drupal\Core\Config\ConfigFactory $config
    *   The config factory service.
    */
-  public function __construct(EntityManagerInterface $entity_manager, Messenger $messenger, Renderer $renderer, ConfigFactory $config) {
+  public function __construct(EntityRepositoryInterface $entity_repository, Messenger $messenger, Renderer $renderer, ConfigFactory $config) {
     $this->messenger = $messenger;
     $this->renderer = $renderer;
     $this->config = $config;
-    parent::__construct($entity_manager);
+    parent::__construct($entity_repository);
   }
 
   /**
@@ -87,7 +88,7 @@ class EventSeriesDeleteForm extends ContentEntityDeleteForm {
       return $this
         ->t('Are you sure you want to delete the @language translation of the @entity-type %label?', [
           '@language' => $entity->language()->getName(),
-          '@entity-type' => $this->getEntity()->getEntityType()->getLowercaseLabel(),
+          '@entity-type' => $this->getEntity()->getEntityType()->getSingularLabel(),
           '%label' => $this->getEntity()->title->value,
         ]);
     }
@@ -110,7 +111,7 @@ class EventSeriesDeleteForm extends ContentEntityDeleteForm {
         ];
 
         $options = [];
-        $timezone = new \DateTimeZone(drupal_get_user_timezone());
+        $timezone = new \DateTimeZone(date_default_timezone_get());
         foreach ($instances as $instance) {
           $date = $instance->date->start_date;
           $date->setTimezone($timezone);
diff --git a/src/Form/EventSeriesForm.php b/src/Form/EventSeriesForm.php
index 6e4767b08f8a1f615e0299aa3f651cb2c9e45290..a7900541c676227d40390654e0cdc030ff447bd9 100644
--- a/src/Form/EventSeriesForm.php
+++ b/src/Form/EventSeriesForm.php
@@ -5,7 +5,6 @@ namespace Drupal\recurring_events\Form;
 use Drupal\Core\Entity\ContentEntityForm;
 use Drupal\Core\Form\FormStateInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
-use Drupal\Core\Entity\EntityManagerInterface;
 use Drupal\recurring_events\EventCreationService;
 use Drupal\Core\Entity\EntityStorageInterface;
 use Drupal\Core\Messenger\Messenger;
@@ -13,6 +12,12 @@ use Drupal\Core\Datetime\DateFormatter;
 use Drupal\Core\Entity\EntityFieldManager;
 use Drupal\Core\Field\FieldTypePluginManager;
 use Drupal\recurring_events\Plugin\Field\FieldWidget\ConsecutiveRecurringDateWidget;
+use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
+use Drupal\Core\Entity\EntityRepositoryInterface;
+use Drupal\Component\Datetime\TimeInterface;
+use Drupal\Core\Session\AccountProxyInterface;
+use Drupal\Core\Config\ConfigFactory;
+use Drupal\Core\Extension\ModuleHandler;
 
 /**
  * Form controller for the eventseries entity create form.
@@ -70,6 +75,34 @@ class EventSeriesForm extends ContentEntityForm {
    */
   protected $fieldTypePluginManager;
 
+  /**
+   * The current user.
+   *
+   * @var \Drupal\Core\Session\AccountProxyInterface
+   */
+  protected $currentUser;
+
+  /**
+   * The time service.
+   *
+   * @var \Drupal\Component\Datetime\TimeInterface
+   */
+  protected $time;
+
+  /**
+   * The module handler service.
+   *
+   * @var \Drupal\Core\Extension\ModuleHandler
+   */
+  protected $moduleHandler;
+
+  /**
+   * The configuration factory.
+   *
+   * @var \Drupal\Core\Config\ConfigFactory
+   */
+  protected $configFactory;
+
   /**
    * {@inheritdoc}
    */
@@ -77,11 +110,16 @@ class EventSeriesForm extends ContentEntityForm {
     return new static(
       $container->get('recurring_events.event_creation_service'),
       $container->get('entity_type.manager')->getStorage('eventseries'),
-      $container->get('entity.manager'),
       $container->get('messenger'),
       $container->get('date.formatter'),
       $container->get('entity_field.manager'),
-      $container->get('plugin.manager.field.field_type')
+      $container->get('plugin.manager.field.field_type'),
+      $container->get('entity.repository'),
+      $container->get('entity_type.bundle.info'),
+      $container->get('datetime.time'),
+      $container->get('current_user'),
+      $container->get('module_handler'),
+      $container->get('config.factory')
     );
   }
 
@@ -92,8 +130,6 @@ class EventSeriesForm extends ContentEntityForm {
    *   The event creation service.
    * @param \Drupal\Core\Entity\EntityStorageInterface $storage
    *   The storage interface.
-   * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
-   *   The entity manager service.
    * @param \Drupal\Core\Messenger\Messenger $messenger
    *   The messenger service.
    * @param \Drupal\Core\Datetime\DateFormatter $date_formatter
@@ -102,15 +138,31 @@ class EventSeriesForm extends ContentEntityForm {
    *   The entity field manager.
    * @param \Drupal\Core\Field\FieldTypePluginManager $field_type_plugin_manager
    *   The field type plugin manager.
+   * @param \Drupal\Core\Entity\EntityRepositoryInterface $entity_repository
+   *   The entity repository interface.
+   * @param \Drupal\Core\Entity\EntityTypeBundleInfoInterface $entity_type_bundle_info
+   *   The entity type bundle info interface.
+   * @param \Drupal\Component\Datetime\TimeInterface $time
+   *   The time interface.
+   * @param \Drupal\Core\Session\AccountProxyInterface $current_user
+   *   The current user.
+   * @param \Drupal\Core\Extension\ModuleHandler $module_handler
+   *   The module handler service.
+   * @param \Drupal\Core\Config\ConfigFactory $config_factory
+   *   The config factory.
    */
-  public function __construct(EventCreationService $creation_service, EntityStorageInterface $storage, EntityManagerInterface $entity_manager, Messenger $messenger, DateFormatter $date_formatter, EntityFieldManager $entity_field_manager, FieldTypePluginManager $field_type_plugin_manager) {
+  public function __construct(EventCreationService $creation_service, EntityStorageInterface $storage, Messenger $messenger, DateFormatter $date_formatter, EntityFieldManager $entity_field_manager, FieldTypePluginManager $field_type_plugin_manager, EntityRepositoryInterface $entity_repository, EntityTypeBundleInfoInterface $entity_type_bundle_info = NULL, TimeInterface $time = NULL, AccountProxyInterface $current_user = NULL, ModuleHandler $module_handler = NULL, ConfigFactory $config_factory = NULL) {
     $this->creationService = $creation_service;
     $this->storage = $storage;
     $this->messenger = $messenger;
     $this->dateFormatter = $date_formatter;
     $this->entityFieldManager = $entity_field_manager;
     $this->fieldTypePluginManager = $field_type_plugin_manager;
-    parent::__construct($entity_manager);
+    $this->time = $time;
+    $this->currentUser = $current_user;
+    $this->moduleHandler = $module_handler;
+    $this->configFactory = $config_factory;
+    parent::__construct($entity_repository, $entity_type_bundle_info, $time);
   }
 
   /**
@@ -119,13 +171,13 @@ class EventSeriesForm extends ContentEntityForm {
   public function buildForm(array $form, FormStateInterface $form_state) {
     $form = parent::buildForm($form, $form_state);
 
-    $config = \Drupal::config('recurring_events.eventseries.config');
-
-    $editing = ($form_state->getBuildInfo()['form_id'] == 'eventseries_edit_form');
+    $config = $this->configFactory->get('recurring_events.eventseries.config');
 
     /* @var $entity \Drupal\recurring_events\Entity\EventSeries */
     $entity = $this->entity;
 
+    $editing = ($form_state->getBuildInfo()['form_id'] == 'eventseries_' . $entity->bundle() . '_edit_form');
+
     $form['custom_date']['#states'] = [
       'visible' => [
         ':input[name="recur_type"]' => ['value' => 'custom'],
@@ -137,7 +189,7 @@ class EventSeriesForm extends ContentEntityForm {
     // necessary fields from the entity form.
     $recur_fields = $this->creationService->getRecurFieldTypes(FALSE);
     $all_recur_fields = $recur_fields;
-    \Drupal::moduleHandler()->alter('recurring_events_recur_field_types', $recur_fields);
+    $this->moduleHandler->alter('recurring_events_recur_field_types', $recur_fields);
 
     $form['recur_type']['widget']['#options'] = $recur_fields;
 
@@ -220,7 +272,7 @@ class EventSeriesForm extends ContentEntityForm {
       '#title' => $this->t('Status'),
       '#attributes' => ['class' => ['entity-meta__header']],
       '#tree' => TRUE,
-      '#access' => \Drupal::currentUser()->hasPermission('administer eventseries'),
+      '#access' => $this->currentUser->hasPermission('administer eventseries'),
     ];
     $form['meta']['published'] = [
       '#type' => 'item',
@@ -254,8 +306,7 @@ class EventSeriesForm extends ContentEntityForm {
 
     /* @var $entity \Drupal\recurring_events\Entity\EventSeries */
     $entity = $this->entity;
-
-    $editing = ($form_state->getBuildInfo()['form_id'] == 'eventseries_edit_form');
+    $editing = ($form_state->getBuildInfo()['form_id'] == 'eventseries_' . $entity->bundle() . '_edit_form');
     $trigger = $form_state->getTriggeringElement();
 
     $ignored_triggers = [
@@ -277,24 +328,19 @@ class EventSeriesForm extends ContentEntityForm {
    */
   public function save(array $form, FormStateInterface $form_state) {
     $entity = $this->getEntity();
-    $original = NULL;
 
     // Save as a new revision if requested to do so.
     if (!$form_state->isValueEmpty('revision') && $form_state->getValue('revision') != FALSE) {
       $entity->setNewRevision();
 
       // If a new revision is created, save the current user as revision author.
-      $entity->setRevisionCreationTime(REQUEST_TIME);
-      $entity->setRevisionUserId(\Drupal::currentUser()->id());
+      $entity->setRevisionCreationTime($this->time->getRequestTime());
+      $entity->setRevisionUserId($this->currentUser->id());
     }
     else {
       $entity->setNewRevision(FALSE);
     }
 
-    if (!$entity->isNew()) {
-      $original = $this->storage->loadUnchanged($entity->id());
-    }
-
     if ($entity->isDefaultTranslation()) {
       $this->messenger->addStatus($this->t('Successfully saved the %name event series', [
         '%name' => $entity->title->value,
diff --git a/src/Form/EventSeriesRevisionDeleteForm.php b/src/Form/EventSeriesRevisionDeleteForm.php
index 8f33e84364520cd309d1a000f31034b919e78da2..ed515e5380495707f7306d29cced86d556d7bd96 100644
--- a/src/Form/EventSeriesRevisionDeleteForm.php
+++ b/src/Form/EventSeriesRevisionDeleteForm.php
@@ -10,6 +10,7 @@ use Drupal\Core\Url;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Drupal\Core\Datetime\DateFormatterInterface;
 use Drupal\Core\Messenger\Messenger;
+use Drupal\Core\StringTranslation\StringTranslationTrait;
 
 /**
  * Provides a form for deleting an eventseries revision.
@@ -18,6 +19,8 @@ use Drupal\Core\Messenger\Messenger;
  */
 class EventSeriesRevisionDeleteForm extends ConfirmFormBase {
 
+  use StringTranslationTrait;
+
   /**
    * The eventseries revision.
    *
@@ -96,7 +99,7 @@ class EventSeriesRevisionDeleteForm extends ConfirmFormBase {
    * {@inheritdoc}
    */
   public function getQuestion() {
-    return t('Are you sure you want to delete the revision from %revision-date?', [
+    return $this->t('Are you sure you want to delete the revision from %revision-date?', [
       '%revision-date' => $this->dateFormatter->format($this->revision->getRevisionCreationTime()),
     ]);
   }
@@ -112,7 +115,7 @@ class EventSeriesRevisionDeleteForm extends ConfirmFormBase {
    * {@inheritdoc}
    */
   public function getConfirmText() {
-    return t('Delete');
+    return $this->t('Delete');
   }
 
   /**
@@ -132,7 +135,7 @@ class EventSeriesRevisionDeleteForm extends ConfirmFormBase {
     $this->eventSeriesStorage->deleteRevision($this->revision->getRevisionId());
 
     $this->logger('content')->notice('eventseries: deleted %title revision %revision.', ['%title' => $this->revision->label(), '%revision' => $this->revision->getRevisionId()]);
-    $this->messenger->addMessage(t('Revision from %revision-date of eventseries %title has been deleted.', [
+    $this->messenger->addMessage($this->t('Revision from %revision-date of eventseries %title has been deleted.', [
       '%revision-date' => $this->dateFormatter->format($this->revision->getRevisionCreationTime()),
       '%title' => $this->revision->label(),
     ]));
diff --git a/src/Form/EventSeriesRevisionRevertForm.php b/src/Form/EventSeriesRevisionRevertForm.php
index e09bb4f4578859945fb2fc7dbbe55b792823bf50..5c2412c58ff12ff092d438bb0f010fa16e7db496 100644
--- a/src/Form/EventSeriesRevisionRevertForm.php
+++ b/src/Form/EventSeriesRevisionRevertForm.php
@@ -10,6 +10,7 @@ use Drupal\Core\Url;
 use Drupal\recurring_events\EventInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Drupal\Core\Messenger\Messenger;
+use Drupal\Core\StringTranslation\StringTranslationTrait;
 
 /**
  * Provides a form for reverting an eventseries revision.
@@ -18,6 +19,8 @@ use Drupal\Core\Messenger\Messenger;
  */
 class EventSeriesRevisionRevertForm extends ConfirmFormBase {
 
+  use StringTranslationTrait;
+
   /**
    * The eventseries revision.
    *
@@ -84,7 +87,7 @@ class EventSeriesRevisionRevertForm extends ConfirmFormBase {
    * {@inheritdoc}
    */
   public function getQuestion() {
-    return t('Are you sure you want to revert to the revision from %revision-date?', ['%revision-date' => $this->dateFormatter->format($this->revision->getRevisionCreationTime())]);
+    return $this->t('Are you sure you want to revert to the revision from %revision-date?', ['%revision-date' => $this->dateFormatter->format($this->revision->getRevisionCreationTime())]);
   }
 
   /**
@@ -98,7 +101,7 @@ class EventSeriesRevisionRevertForm extends ConfirmFormBase {
    * {@inheritdoc}
    */
   public function getConfirmText() {
-    return t('Revert');
+    return $this->t('Revert');
   }
 
   /**
@@ -127,11 +130,11 @@ class EventSeriesRevisionRevertForm extends ConfirmFormBase {
     $original_revision_timestamp = $this->revision->getRevisionCreationTime();
 
     $this->revision = $this->prepareRevertedRevision($this->revision, $form_state);
-    $this->revision->revision_log = t('Copy of the revision from %date.', ['%date' => $this->dateFormatter->format($original_revision_timestamp)]);
+    $this->revision->revision_log = $this->t('Copy of the revision from %date.', ['%date' => $this->dateFormatter->format($original_revision_timestamp)]);
     $this->revision->save();
 
     $this->logger('content')->notice('eventseries: reverted %title revision %revision.', ['%title' => $this->revision->label(), '%revision' => $this->revision->getRevisionId()]);
-    $this->messenger->addMessage(t('eventseries %title has been reverted to the revision from %revision-date.', [
+    $this->messenger->addMessage($this->t('eventseries %title has been reverted to the revision from %revision-date.', [
       '%title' => $this->revision->label(),
       '%revision-date' => $this->dateFormatter->format($original_revision_timestamp),
     ]));
@@ -155,7 +158,7 @@ class EventSeriesRevisionRevertForm extends ConfirmFormBase {
   protected function prepareRevertedRevision(EventInterface $revision, FormStateInterface $form_state) {
     $revision->setNewRevision();
     $revision->isDefaultRevision(TRUE);
-    $revision->setRevisionCreationTime(REQUEST_TIME);
+    $revision->setRevisionCreationTime(\Drupal::time()->getRequestTime());
 
     return $revision;
   }
diff --git a/src/Form/EventSeriesRevisionRevertTranslationForm.php b/src/Form/EventSeriesRevisionRevertTranslationForm.php
index 17a15ac2c98bfea6fd9086d67ffafa2cceeaaf52..448b3c681de8bc7573ead0331e5454200bf56fb7 100644
--- a/src/Form/EventSeriesRevisionRevertTranslationForm.php
+++ b/src/Form/EventSeriesRevisionRevertTranslationForm.php
@@ -8,6 +8,7 @@ use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Language\LanguageManagerInterface;
 use Drupal\recurring_events\EventInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
+use Drupal\Component\Datetime\TimeInterface;
 
 /**
  * Provides form to revert an eventseries revision for a single translation.
@@ -30,6 +31,13 @@ class EventSeriesRevisionRevertTranslationForm extends EventSeriesRevisionRevert
    */
   protected $languageManager;
 
+  /**
+   * The time service.
+   *
+   * @var \Drupal\Component\Datetime\TimeInterface
+   */
+  protected $time;
+
   /**
    * Constructs a new EventSeriesRevisionRevertTranslationForm.
    *
@@ -39,10 +47,13 @@ class EventSeriesRevisionRevertTranslationForm extends EventSeriesRevisionRevert
    *   The date formatter service.
    * @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
    *   The language manager.
+   * @param \Drupal\Component\Datetime\TimeInterface $time
+   *   The time service.
    */
-  public function __construct(EntityStorageInterface $entity_storage, DateFormatterInterface $date_formatter, LanguageManagerInterface $language_manager) {
+  public function __construct(EntityStorageInterface $entity_storage, DateFormatterInterface $date_formatter, LanguageManagerInterface $language_manager, TimeInterface $time) {
     parent::__construct($entity_storage, $date_formatter);
     $this->languageManager = $language_manager;
+    $this->time = $time;
   }
 
   /**
@@ -52,7 +63,8 @@ class EventSeriesRevisionRevertTranslationForm extends EventSeriesRevisionRevert
     return new static(
       $container->get('entity.manager')->getStorage('eventseries'),
       $container->get('date.formatter'),
-      $container->get('language_manager')
+      $container->get('language_manager'),
+      $container->get('datetime.time')
     );
   }
 
@@ -67,7 +79,7 @@ class EventSeriesRevisionRevertTranslationForm extends EventSeriesRevisionRevert
    * {@inheritdoc}
    */
   public function getQuestion() {
-    return t('Are you sure you want to revert @language translation to the revision from %revision-date?', ['@language' => $this->languageManager->getLanguageName($this->langcode), '%revision-date' => $this->dateFormatter->format($this->revision->getRevisionCreationTime())]);
+    return $this->t('Are you sure you want to revert @language translation to the revision from %revision-date?', ['@language' => $this->languageManager->getLanguageName($this->langcode), '%revision-date' => $this->dateFormatter->format($this->revision->getRevisionCreationTime())]);
   }
 
   /**
@@ -106,7 +118,7 @@ class EventSeriesRevisionRevertTranslationForm extends EventSeriesRevisionRevert
 
     $latest_revision_translation->setNewRevision();
     $latest_revision_translation->isDefaultRevision(TRUE);
-    $revision->setRevisionCreationTime(REQUEST_TIME);
+    $revision->setRevisionCreationTime($this->time->getRequestTime());
 
     return $latest_revision_translation;
   }
diff --git a/src/Form/EventSeriesSettingsForm.php b/src/Form/EventSeriesSettingsForm.php
index 4e7762ac4546b2dc87d82e6875b64297d3001468..3e26270c4ef6c879e80b882066d19714837c1063 100644
--- a/src/Form/EventSeriesSettingsForm.php
+++ b/src/Form/EventSeriesSettingsForm.php
@@ -6,6 +6,8 @@ use Drupal\Core\Form\ConfigFormBase;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Url;
 use Drupal\Core\Link;
+use Drupal\recurring_events\EventCreationService;
+use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
  * Class EventSeriesSettingsForm.
@@ -14,6 +16,32 @@ use Drupal\Core\Link;
  */
 class EventSeriesSettingsForm extends ConfigFormBase {
 
+  /**
+   * The event creation service.
+   *
+   * @var \Drupal\recurring_events\EventCreationService
+   */
+  protected $creationService;
+
+  /**
+   * Constructs a new EventSeriesSettingsForm.
+   *
+   * @param \Drupal\recurring_events\EventCreationService $creation_service
+   *   The event creation service.
+   */
+  public function __construct(EventCreationService $creation_service) {
+    $this->creationService = $creation_service;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container) {
+    return new static(
+      $container->get('recurring_events.event_creation_service')
+    );
+  }
+
   /**
    * Returns a unique string identifying the form.
    *
@@ -128,13 +156,13 @@ class EventSeriesSettingsForm extends ConfigFormBase {
     ];
 
     $days = [
-      'monday' => t('Monday'),
-      'tuesday' => t('Tuesday'),
-      'wednesday' => t('Wednesday'),
-      'thursday' => t('Thursday'),
-      'friday' => t('Friday'),
-      'saturday' => t('Saturday'),
-      'sunday' => t('Sunday'),
+      'monday' => $this->t('Monday'),
+      'tuesday' => $this->t('Tuesday'),
+      'wednesday' => $this->t('Wednesday'),
+      'thursday' => $this->t('Thursday'),
+      'friday' => $this->t('Friday'),
+      'saturday' => $this->t('Saturday'),
+      'sunday' => $this->t('Sunday'),
     ];
 
     $form['creation']['days'] = [
@@ -164,7 +192,7 @@ class EventSeriesSettingsForm extends ConfigFormBase {
       '#default_value' => $config->get('includes'),
     ];
 
-    $fields = \Drupal::service('recurring_events.event_creation_service')->getRecurFieldTypes(FALSE);
+    $fields = $this->creationService->getRecurFieldTypes(FALSE);
 
     $form['creation']['enabled_fields'] = [
       '#type' => 'checkboxes',
diff --git a/src/Form/EventSeriesTypeDeleteForm.php b/src/Form/EventSeriesTypeDeleteForm.php
new file mode 100644
index 0000000000000000000000000000000000000000..66dab774e9e7b55f0284ea6a773beff30ffc5c3b
--- /dev/null
+++ b/src/Form/EventSeriesTypeDeleteForm.php
@@ -0,0 +1,105 @@
+<?php
+
+namespace Drupal\recurring_events\Form;
+
+use Drupal\Core\Entity\EntityConfirmFormBase;
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Url;
+use Drupal\Core\Messenger\Messenger;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * Builds the form to delete Event series type entities.
+ */
+class EventSeriesTypeDeleteForm extends EntityConfirmFormBase {
+
+  /**
+   * The messenger service.
+   *
+   * @var \Drupal\Core\Messenger\Messenger
+   */
+  protected $messenger;
+
+  /**
+   * Construct a EventSeriesTypeDeleteForm.
+   *
+   * @param \Drupal\Core\Messenger\Messenger $messenger
+   *   The messenger service.
+   */
+  public function __construct(Messenger $messenger) {
+    $this->messenger = $messenger;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container) {
+    return new static(
+      $container->get('messenger')
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getQuestion() {
+    return $this->t('Are you sure you want to delete %name?', ['%name' => $this->entity->label()]);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getDescription() {
+    $descriptions = [];
+    $instance_type = \Drupal::entityTypeManager()->getStorage('eventinstance_type')->load($this->entity->id());
+
+    if (!empty($instance_type)) {
+      $descriptions[] = $this->t('Deleting this event series type will also delete the corresponding event instance type.');
+    }
+
+    if (\Drupal::moduleHandler()->moduleExists('recurring_events_registration')) {
+      $registrant_types = \Drupal::entityTypeManager()->getStorage('registrant_type')->load($this->entity->id());
+      if (!empty($registrant_types)) {
+        $descriptions[] = $this->t('Deleting this event series type will also delete the corresponding registrant type.');
+      }
+    }
+
+    return implode("\r\n", $descriptions);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getCancelUrl() {
+    return new Url('entity.eventseries_type.collection');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getConfirmText() {
+    return $this->t('Delete');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function submitForm(array &$form, FormStateInterface $form_state) {
+    $this->entity->delete();
+
+    $this->messenger->addMessage(
+      $this->t('Succesfully deleted @type: @label.',
+        [
+          '@type' => $this->entity->bundle(),
+          '@label' => $this->entity->label(),
+        ]
+      )
+    );
+
+    \Drupal::cache('menu')->invalidateAll();
+    \Drupal::service('plugin.manager.menu.link')->rebuild();
+
+    $form_state->setRedirectUrl($this->getCancelUrl());
+  }
+
+}
diff --git a/src/Form/EventSeriesTypeForm.php b/src/Form/EventSeriesTypeForm.php
new file mode 100644
index 0000000000000000000000000000000000000000..93d1e2d9f87b74bb29c60a65909a06cee0a007fc
--- /dev/null
+++ b/src/Form/EventSeriesTypeForm.php
@@ -0,0 +1,98 @@
+<?php
+
+namespace Drupal\recurring_events\Form;
+
+use Drupal\Core\Entity\EntityForm;
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Messenger\Messenger;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * Class EventSeriesTypeForm.
+ */
+class EventSeriesTypeForm extends EntityForm {
+
+  /**
+   * The messenger service.
+   *
+   * @var \Drupal\Core\Messenger\Messenger
+   */
+  protected $messenger;
+
+  /**
+   * Constructs a new EventSeriesTypeForm.
+   *
+   * @param \Drupal\Core\Messenger\Messenger $messenger
+   *   The messenger service.
+   */
+  public function __construct(Messenger $messenger) {
+    $this->messenger = $messenger;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container) {
+    return new static(
+      $container->get('messenger')
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function form(array $form, FormStateInterface $form_state) {
+    $form = parent::form($form, $form_state);
+
+    $eventseries_type = $this->entity;
+    $form['label'] = [
+      '#type' => 'textfield',
+      '#title' => $this->t('Label'),
+      '#maxlength' => 255,
+      '#default_value' => $eventseries_type->label(),
+      '#description' => $this->t("Label for the Event series type."),
+      '#required' => TRUE,
+    ];
+
+    $form['id'] = [
+      '#type' => 'machine_name',
+      '#default_value' => $eventseries_type->id(),
+      '#machine_name' => [
+        'exists' => '\Drupal\recurring_events\Entity\EventSeriesType::load',
+      ],
+      '#disabled' => !$eventseries_type->isNew(),
+    ];
+
+    $form['description'] = [
+      '#title' => $this->t('Description'),
+      '#type' => 'textarea',
+      '#default_value' => $eventseries_type->getDescription(),
+      '#description' => $this->t('This text will be displayed on the <em>Add event</em> page.'),
+    ];
+
+    return $form;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function save(array $form, FormStateInterface $form_state) {
+    $eventseries_type = $this->entity;
+    $status = $eventseries_type->save();
+
+    switch ($status) {
+      case SAVED_NEW:
+        $this->messenger->addMessage($this->t('Created the %label event series type.', [
+          '%label' => $eventseries_type->label(),
+        ]));
+        break;
+
+      default:
+        $this->messenger->addMessage($this->t('Saved the %label event series type.', [
+          '%label' => $eventseries_type->label(),
+        ]));
+    }
+    $form_state->setRedirectUrl($eventseries_type->toUrl('collection'));
+  }
+
+}
diff --git a/src/Form/FieldInheritanceDeleteForm.php b/src/Form/FieldInheritanceDeleteForm.php
deleted file mode 100644
index 1f140fee8655a2f8c10d13bb7dd88a8a6555f195..0000000000000000000000000000000000000000
--- a/src/Form/FieldInheritanceDeleteForm.php
+++ /dev/null
@@ -1,92 +0,0 @@
-<?php
-
-namespace Drupal\recurring_events\Form;
-
-use Drupal\Core\Entity\EntityConfirmFormBase;
-use Drupal\Core\Form\FormStateInterface;
-use Drupal\Core\Url;
-use Drupal\Core\Messenger\Messenger;
-use Symfony\Component\DependencyInjection\ContainerInterface;
-use Drupal\Core\Entity\EntityFieldManager;
-
-/**
- * Builds the form to delete Field inheritance entities.
- */
-class FieldInheritanceDeleteForm extends EntityConfirmFormBase {
-
-  /**
-   * The messenger service.
-   *
-   * @var \Drupal\Core\Messenger\Messenger
-   */
-  protected $messenger;
-
-  /**
-   * The entity field manager service.
-   *
-   * @var \Drupal\Core\Entity\EntityFieldManager
-   */
-  protected $entityFieldManager;
-
-  /**
-   * Construct an EventSeriesDeleteForm.
-   *
-   * @param \Drupal\Core\Messenger\Messenger $messenger
-   *   The messenger service.
-   * @param \Drupal\Core\Entity\EntityFieldManager $entity_field_manager
-   *   The entity field manager service.
-   */
-  public function __construct(Messenger $messenger, EntityFieldManager $entity_field_manager) {
-    $this->messenger = $messenger;
-    $this->entityFieldManager = $entity_field_manager;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public static function create(ContainerInterface $container) {
-    return new static(
-      $container->get('messenger'),
-      $container->get('entity_field.manager')
-    );
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getQuestion() {
-    return $this->t('Are you sure you want to delete %name?', ['%name' => $this->entity->label()]);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getCancelUrl() {
-    return new Url('entity.field_inheritance.collection');
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getConfirmText() {
-    return $this->t('Delete');
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function submitForm(array &$form, FormStateInterface $form_state) {
-    $this->entity->delete();
-
-    $this->messenger->addMessage(
-      $this->t('content @type: deleted @label.', [
-        '@type' => $this->entity->bundle(),
-        '@label' => $this->entity->label(),
-      ])
-    );
-
-    $this->entityFieldManager->clearCachedFieldDefinitions();
-    $form_state->setRedirectUrl($this->getCancelUrl());
-  }
-
-}
diff --git a/src/Form/FieldInheritanceForm.php b/src/Form/FieldInheritanceForm.php
deleted file mode 100644
index b5d7fa16e48709ad015e805bed236e28eefe33fa..0000000000000000000000000000000000000000
--- a/src/Form/FieldInheritanceForm.php
+++ /dev/null
@@ -1,230 +0,0 @@
-<?php
-
-namespace Drupal\recurring_events\Form;
-
-use Drupal\Core\Entity\EntityForm;
-use Drupal\Core\Form\FormStateInterface;
-use Drupal\Core\Messenger\Messenger;
-use Symfony\Component\DependencyInjection\ContainerInterface;
-use Drupal\Core\Entity\EntityFieldManager;
-use Drupal\recurring_events\FieldInheritancePluginManager;
-
-/**
- * Class FieldInheritanceForm.
- */
-class FieldInheritanceForm extends EntityForm {
-
-  /**
-   * The messenger service.
-   *
-   * @var \Drupal\Core\Messenger\Messenger
-   */
-  protected $messenger;
-
-  /**
-   * The entity field manager service.
-   *
-   * @var \Drupal\Core\Entity\EntityFieldManager
-   */
-  protected $entityFieldManager;
-
-  /**
-   * The field inheritance plugin manager.
-   *
-   * @var \Drupal\recurring_events\FieldInheritancePluginManager
-   */
-  protected $fieldInheritance;
-
-  /**
-   * Construct an FieldInheritanceForm.
-   *
-   * @param \Drupal\Core\Messenger\Messenger $messenger
-   *   The messenger service.
-   * @param \Drupal\Core\Entity\EntityFieldManager $entity_field_manager
-   *   The entity field manager service.
-   * @param \Drupal\recurring_events\FieldInheritancePluginManager $field_inheritance
-   *   The field inheritance plugin manager.
-   */
-  public function __construct(Messenger $messenger, EntityFieldManager $entity_field_manager, FieldInheritancePluginManager $field_inheritance) {
-    $this->messenger = $messenger;
-    $this->entityFieldManager = $entity_field_manager;
-    $this->fieldInheritance = $field_inheritance;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public static function create(ContainerInterface $container) {
-    return new static(
-      $container->get('messenger'),
-      $container->get('entity_field.manager'),
-      $container->get('plugin.manager.field_inheritance')
-    );
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function form(array $form, FormStateInterface $form_state) {
-    $form = parent::form($form, $form_state);
-
-    $field_inheritance = $this->entity;
-    $form['label'] = [
-      '#type' => 'textfield',
-      '#title' => $this->t('Label'),
-      '#maxlength' => 255,
-      '#default_value' => $field_inheritance->label(),
-      '#description' => $this->t("Label for the Field inheritance."),
-      '#required' => TRUE,
-    ];
-
-    $form['id'] = [
-      '#type' => 'machine_name',
-      '#default_value' => $field_inheritance->id(),
-      '#machine_name' => [
-        'exists' => '\Drupal\recurring_events\Entity\FieldInheritance::load',
-      ],
-      '#disabled' => !$field_inheritance->isNew(),
-    ];
-
-    $help = [
-      $this->t('<b>Inherit</b> - Pull field data directly from the series.'),
-      $this->t('<b>Prepend</b> - Place instance data above series data.'),
-      $this->t('<b>Append</b> - Place instance data below series data.'),
-      $this->t('<b>Fallback</b> - Show instance data, if set, otherwise show series data.'),
-    ];
-
-    $form['type'] = [
-      '#type' => 'select',
-      '#title' => $this->t('Inheritance Strategy'),
-      '#description' => $this->t('Select the method/strategy used to inherit data.'),
-      '#options' => [
-        'inherit' => $this->t('Inherit'),
-        'prepend' => $this->t('Prepend'),
-        'append' => $this->t('Append'),
-        'fallback' => $this->t('Fallback'),
-      ],
-      '#required' => TRUE,
-      '#default_value' => $field_inheritance->type() ?: 'inherit',
-    ];
-    $form['information'] = [
-      '#type' => 'markup',
-      '#prefix' => '<p>',
-      '#markup' => implode('</p><p>', $help),
-      '#suffix' => '</p>',
-    ];
-
-    $series_fields = array_keys($this->entityFieldManager->getFieldDefinitions('eventseries', 'eventseries'));
-    $series_fields = array_combine($series_fields, $series_fields);
-
-    $form['sourceField'] = [
-      '#type' => 'select',
-      '#title' => $this->t('Source/Series Field'),
-      '#description' => $this->t('Select the field on the series from which to inherit data.'),
-      '#options' => $series_fields,
-      '#required' => TRUE,
-      '#default_value' => $field_inheritance->sourceField(),
-    ];
-
-    $instance_fields = array_keys($this->entityFieldManager->getFieldDefinitions('eventinstance', 'eventinstance'));
-    $instance_fields = array_combine($instance_fields, $instance_fields);
-
-    // You should never be able to use the inherited field as part of an
-    // inheritance as that creates an infinite loop.
-    if (!empty($field_inheritance->id()) && !empty($instance_fields[$field_inheritance->id()])) {
-      unset($instance_fields[$field_inheritance->id()]);
-    }
-
-    $form['entityField'] = [
-      '#type' => 'select',
-      '#title' => $this->t('Entity/Instance Field'),
-      '#description' => $this->t('Select the field on the instance to use during inheritance.'),
-      '#options' => $instance_fields,
-      '#states' => [
-        'visible' => [
-          'select[name="type"]' => ['!value' => 'inherit'],
-        ],
-        'required' => [
-          'select[name="type"]' => ['!value' => 'inherit'],
-        ],
-      ],
-      '#default_value' => $field_inheritance->entityField(),
-    ];
-
-    $plugins = array_keys($this->fieldInheritance->getDefinitions());
-    $plugins = array_combine($plugins, $plugins);
-
-    $form['plugin'] = [
-      '#type' => 'select',
-      '#title' => $this->t('Inheritance Plugin'),
-      '#description' => $this->t('Select the plugin used to perform the inheritance.'),
-      '#options' => $plugins,
-      '#required' => TRUE,
-      '#default_value' => $field_inheritance->plugin(),
-    ];
-
-    return $form;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function validateForm(array &$form, FormStateInterface $form_state) {
-    parent::validateForm($form, $form_state);
-    $values = $form_state->getValues();
-
-    if (!empty($values['sourceField']) && !empty($values['entityField'])) {
-      $series_definitions = $this->entityFieldManager->getFieldDefinitions('eventseries', 'eventseries');
-      $instance_definitions = $this->entityFieldManager->getFieldDefinitions('eventinstance', 'eventinstance');
-
-      if ($series_definitions[$values['sourceField']]->getType() !== $instance_definitions[$values['entityField']]->getType()) {
-        $message = $this->t('Source and entity field definition types must be the same to inherit data. Source - @source_name type: @source_type. Entity - @entity_name type: @entity_type', [
-          '@source_name' => $values['sourceField'],
-          '@source_type' => $series_definitions[$values['sourceField']]->getType(),
-          '@entity_name' => $values['entityField'],
-          '@entity_type' => $instance_definitions[$values['entityField']]->getType(),
-        ]);
-        $form_state->setErrorByName('sourceField', $message);
-        $form_state->setErrorByName('entityField', $message);
-      }
-
-      $plugin_definition = $this->fieldInheritance->getDefinition($values['plugin']);
-      $field_types = $plugin_definition['types'];
-
-      if (!in_array($series_definitions[$values['sourceField']]->getType(), $field_types)) {
-        $message = $this->t('The selected plugin @plugin does not support @source_type fields. The supported field types are: @field_types', [
-          '@plugin' => $values['plugin'],
-          '@source_type' => $series_definitions[$values['sourceField']]->getType(),
-          '@field_types' => implode(',', $field_types),
-        ]);
-        $form_state->setErrorByName('sourceField', $message);
-        $form_state->setErrorByName('plugin', $message);
-      }
-
-    }
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function save(array $form, FormStateInterface $form_state) {
-    $field_inheritance = $this->entity;
-    $status = $field_inheritance->save();
-
-    switch ($status) {
-      case SAVED_NEW:
-        $this->messenger->addMessage($this->t('Created the %label Field inheritance.', [
-          '%label' => $field_inheritance->label(),
-        ]));
-        break;
-
-      default:
-        $this->messenger->addMessage($this->t('Saved the %label Field inheritance.', [
-          '%label' => $field_inheritance->label(),
-        ]));
-    }
-    $this->entityFieldManager->clearCachedFieldDefinitions();
-    $form_state->setRedirectUrl($field_inheritance->toUrl('collection'));
-  }
-
-}
diff --git a/src/IncludedDatesHtmlRouteProvider.php b/src/IncludedDatesHtmlRouteProvider.php
index 6fe244930c006464a403442b921f41be653267ad..b7bebda5863dca844bcbadf792b8c67084076f4a 100644
--- a/src/IncludedDatesHtmlRouteProvider.php
+++ b/src/IncludedDatesHtmlRouteProvider.php
@@ -4,7 +4,6 @@ namespace Drupal\recurring_events;
 
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Entity\Routing\AdminHtmlRouteProvider;
-use Symfony\Component\Routing\Route;
 
 /**
  * Provides routes for Included dates entities.
@@ -19,9 +18,6 @@ class IncludedDatesHtmlRouteProvider extends AdminHtmlRouteProvider {
    */
   public function getRoutes(EntityTypeInterface $entity_type) {
     $collection = parent::getRoutes($entity_type);
-
-    // Provide your custom entity routes here.
-
     return $collection;
   }
 
diff --git a/src/Plugin/Field/FieldFormatter/EventInstanceDateFormatter.php b/src/Plugin/Field/FieldFormatter/EventInstanceDateFormatter.php
index ace9c0f5ef6b89b20e3c5936a1f9d417cfc940c2..9d1103ee23dc9da29b688df5c24386e321a78115 100644
--- a/src/Plugin/Field/FieldFormatter/EventInstanceDateFormatter.php
+++ b/src/Plugin/Field/FieldFormatter/EventInstanceDateFormatter.php
@@ -9,6 +9,7 @@ use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Field\FieldDefinitionInterface;
 use Drupal\Core\Url;
 use Drupal\Core\Link;
+use Drupal\Core\StringTranslation\StringTranslationTrait;
 
 /**
  * Plugin implementation of the 'recurring events eventinstance date' formatter.
@@ -24,6 +25,8 @@ use Drupal\Core\Link;
  */
 class EventInstanceDateFormatter extends EntityReferenceFormatterBase {
 
+  use StringTranslationTrait;
+
   /**
    * {@inheritdoc}
    */
@@ -40,7 +43,7 @@ class EventInstanceDateFormatter extends EntityReferenceFormatterBase {
    */
   public function settingsForm(array $form, FormStateInterface $form_state) {
     $elements['link'] = [
-      '#title' => t('Link date to the referenced entity'),
+      '#title' => $this->t('Link date to the referenced entity'),
       '#type' => 'checkbox',
       '#default_value' => $this->getSetting('link'),
     ];
@@ -50,7 +53,7 @@ class EventInstanceDateFormatter extends EntityReferenceFormatterBase {
 
     $elements['date_format'] = [
       '#type' => 'textfield',
-      '#title' => t('Date Format @link', [
+      '#title' => $this->t('Date Format @link', [
         '@link' => $php_date_link->toString(),
       ]),
       '#required' => TRUE,
@@ -58,9 +61,9 @@ class EventInstanceDateFormatter extends EntityReferenceFormatterBase {
     ];
 
     $elements['separator'] = [
-      '#title' => t('Separator'),
+      '#title' => $this->t('Separator'),
       '#type' => 'textfield',
-      '#description' => t('Enter the separator to use between start and end dates.'),
+      '#description' => $this->t('Enter the separator to use between start and end dates.'),
       '#default_value' => $this->getSetting('separator'),
     ];
 
@@ -72,11 +75,11 @@ class EventInstanceDateFormatter extends EntityReferenceFormatterBase {
    */
   public function settingsSummary() {
     $summary = [];
-    $summary[] = $this->getSetting('link') ? t('Link to the referenced entity') : t('No link');
-    $summary[] = t('Format: %format', [
+    $summary[] = $this->getSetting('link') ? $this->t('Link to the referenced entity') : $this->t('No link');
+    $summary[] = $this->t('Format: %format', [
       '%format' => $this->getSetting('date_format'),
     ]);
-    $summary[] = t('Separator: %separator', [
+    $summary[] = $this->t('Separator: %separator', [
       '%separator' => $this->getSetting('separator'),
     ]);
     return $summary;
@@ -98,7 +101,7 @@ class EventInstanceDateFormatter extends EntityReferenceFormatterBase {
 
     foreach ($this->getEntitiesToView($items, $langcode) as $delta => $entity) {
       $date_string = '';
-      $user_timezone = new \DateTimeZone(drupal_get_user_timezone());
+      $user_timezone = new \DateTimeZone(date_default_timezone_get());
       if (!empty($entity->date->start_date) && !empty($entity->date->end_date)) {
         /** @var \Drupal\Core\Datetime\DrupalDateTime $start_date */
         $start_date = $entity->date->start_date;
@@ -152,6 +155,15 @@ class EventInstanceDateFormatter extends EntityReferenceFormatterBase {
       $elements[$delta]['#cache']['tags'] = $entity->getCacheTags();
     }
 
+    usort($elements, function ($a, $b) {
+      $a_date = $a['#options']['entity']->date->start_date->getTimestamp();
+      $b_date = $b['#options']['entity']->date->start_date->getTimestamp();
+      if ($a_date == $b_date) {
+        return 0;
+      }
+      return ($a_date < $b_date) ? -1 : 1;
+    });
+
     return $elements;
   }
 
diff --git a/src/Plugin/Field/FieldType/ConsecutiveRecurringDate.php b/src/Plugin/Field/FieldType/ConsecutiveRecurringDate.php
index 95bf5ef37fef4352d9115822a365a989eb680595..5b001517dd3c09d80ba05033dee3db16d7393492 100644
--- a/src/Plugin/Field/FieldType/ConsecutiveRecurringDate.php
+++ b/src/Plugin/Field/FieldType/ConsecutiveRecurringDate.php
@@ -137,8 +137,7 @@ class ConsecutiveRecurringDate extends DateRangeItem implements RecurringEventsF
   public static function convertFormConfigToArray(FormStateInterface $form_state) {
     $config = [];
 
-    $user_timezone = new \DateTimeZone(drupal_get_user_timezone());
-    $utc_timezone = new \DateTimeZone(DateTimeItemInterface::STORAGE_TIMEZONE);
+    $user_timezone = new \DateTimeZone(date_default_timezone_get());
     $user_input = $form_state->getUserInput();
 
     if (!empty($user_input['consecutive_recurring_date'][0]['value']['date'])
@@ -239,7 +238,7 @@ class ConsecutiveRecurringDate extends DateRangeItem implements RecurringEventsF
    * {@inheritdoc}
    */
   public static function calculateInstances(array $form_data) {
-    $dates = $events_to_create = [];
+    $events_to_create = [];
     $utc_timezone = new \DateTimeZone(DateTimeItemInterface::STORAGE_TIMEZONE);
 
     $daily_dates = static::findDailyDatesBetweenDates($form_data['start_date'], $form_data['end_date']);
@@ -342,7 +341,7 @@ class ConsecutiveRecurringDate extends DateRangeItem implements RecurringEventsF
     $count = 0;
 
     $max_time = clone $date;
-    $user_timezone = new \DateTimeZone(drupal_get_user_timezone());
+    $user_timezone = new \DateTimeZone(date_default_timezone_get());
     $utc_timezone = new \DateTimeZone(DateTimeItemInterface::STORAGE_TIMEZONE);
 
     $time_parts = static::convertTimeTo24hourFormat($form_data['end_time']);
diff --git a/src/Plugin/Field/FieldType/DailyRecurringDate.php b/src/Plugin/Field/FieldType/DailyRecurringDate.php
index d59c68d26e3578063eb9b0c5523ef7cbb5ad2f49..5917817d55c4dbb4ac34cda7be6f5d22aa71f5ae 100644
--- a/src/Plugin/Field/FieldType/DailyRecurringDate.php
+++ b/src/Plugin/Field/FieldType/DailyRecurringDate.php
@@ -91,8 +91,7 @@ class DailyRecurringDate extends DateRangeItem implements RecurringEventsFieldTy
   public static function convertFormConfigToArray(FormStateInterface $form_state) {
     $config = [];
 
-    $user_timezone = new \DateTimeZone(drupal_get_user_timezone());
-    $utc_timezone = new \DateTimeZone(DateTimeItemInterface::STORAGE_TIMEZONE);
+    $user_timezone = new \DateTimeZone(date_default_timezone_get());
     $user_input = $form_state->getUserInput();
 
     $time = $user_input['daily_recurring_date'][0]['time'];
@@ -157,7 +156,7 @@ class DailyRecurringDate extends DateRangeItem implements RecurringEventsFieldTy
    * {@inheritdoc}
    */
   public static function calculateInstances(array $form_data) {
-    $dates = $events_to_create = [];
+    $events_to_create = [];
     $utc_timezone = new \DateTimeZone(DateTimeItemInterface::STORAGE_TIMEZONE);
 
     $daily_dates = static::findDailyDatesBetweenDates($form_data['start_date'], $form_data['end_date']);
diff --git a/src/Plugin/Field/FieldType/MonthlyRecurringDate.php b/src/Plugin/Field/FieldType/MonthlyRecurringDate.php
index 21154441d854ea4004f803fec47f6d7f3363105e..e28759093241c7e729273a5fe35b9ee93272520a 100644
--- a/src/Plugin/Field/FieldType/MonthlyRecurringDate.php
+++ b/src/Plugin/Field/FieldType/MonthlyRecurringDate.php
@@ -115,8 +115,7 @@ class MonthlyRecurringDate extends WeeklyRecurringDate implements RecurringEvent
   public static function convertFormConfigToArray(FormStateInterface $form_state) {
     $config = [];
 
-    $user_timezone = new \DateTimeZone(drupal_get_user_timezone());
-    $utc_timezone = new \DateTimeZone(DateTimeItemInterface::STORAGE_TIMEZONE);
+    $user_timezone = new \DateTimeZone(date_default_timezone_get());
     $user_input = $form_state->getUserInput();
 
     $time = $user_input['monthly_recurring_date'][0]['time'];
diff --git a/src/Plugin/Field/FieldType/WeeklyRecurringDate.php b/src/Plugin/Field/FieldType/WeeklyRecurringDate.php
index 28cc10494a484e40adadc078d957eb98f82df67d..ef29a5ff60a32a89b6426fd56f6e8f4c4a49c001 100644
--- a/src/Plugin/Field/FieldType/WeeklyRecurringDate.php
+++ b/src/Plugin/Field/FieldType/WeeklyRecurringDate.php
@@ -80,8 +80,7 @@ class WeeklyRecurringDate extends DailyRecurringDate implements RecurringEventsF
   public static function convertFormConfigToArray(FormStateInterface $form_state) {
     $config = [];
 
-    $user_timezone = new \DateTimeZone(drupal_get_user_timezone());
-    $utc_timezone = new \DateTimeZone(DateTimeItemInterface::STORAGE_TIMEZONE);
+    $user_timezone = new \DateTimeZone(date_default_timezone_get());
     $user_input = $form_state->getUserInput();
 
     $time = $user_input['weekly_recurring_date'][0]['time'];
diff --git a/src/Plugin/Field/FieldWidget/ConsecutiveRecurringDateWidget.php b/src/Plugin/Field/FieldWidget/ConsecutiveRecurringDateWidget.php
index 0aee37ef6b45772b40854ae6226a92295e4bf334..6800388b5ee7e119c76e8272e12c806a153387f4 100644
--- a/src/Plugin/Field/FieldWidget/ConsecutiveRecurringDateWidget.php
+++ b/src/Plugin/Field/FieldWidget/ConsecutiveRecurringDateWidget.php
@@ -11,6 +11,7 @@ use Drupal\recurring_events\Plugin\RecurringEventsFieldTrait;
 use Drupal\Core\Ajax\AjaxResponse;
 use Drupal\Core\Ajax\HtmlCommand;
 use Drupal\recurring_events\Plugin\Field\FieldType\ConsecutiveRecurringDate;
+use Drupal\Core\StringTranslation\StringTranslationTrait;
 
 /**
  * Plugin implementation of the 'consecutive recurring date' widget.
@@ -26,6 +27,7 @@ use Drupal\recurring_events\Plugin\Field\FieldType\ConsecutiveRecurringDate;
 class ConsecutiveRecurringDateWidget extends DateRangeDefaultWidget {
 
   use RecurringEventsFieldTrait;
+  use StringTranslationTrait;
 
   /**
    * {@inheritdoc}
@@ -42,8 +44,9 @@ class ConsecutiveRecurringDateWidget extends DateRangeDefaultWidget {
       ],
     ];
     $element['#element_validate'][] = [$this, 'validateThreshold'];
+    $element['#element_validate'][] = [$this, 'validateForm'];
 
-    $element['value']['#title'] = t('Create Events Between');
+    $element['value']['#title'] = $this->t('Create Events Between');
     $element['value']['#weight'] = 1;
     $element['value']['#date_date_format'] = DateTimeItemInterface::DATE_STORAGE_FORMAT;
     $element['value']['#date_date_element'] = 'date';
@@ -55,7 +58,7 @@ class ConsecutiveRecurringDateWidget extends DateRangeDefaultWidget {
       'wrapper' => 'eventseries-edit-form',
     ];
 
-    $element['end_value']['#title'] = t('And');
+    $element['end_value']['#title'] = $this->t('And');
     $element['end_value']['#weight'] = 2;
     $element['end_value']['#date_date_format'] = DateTimeItemInterface::DATE_STORAGE_FORMAT;
     $element['end_value']['#date_date_element'] = 'date';
@@ -73,7 +76,7 @@ class ConsecutiveRecurringDateWidget extends DateRangeDefaultWidget {
     $end_time = end($time_keys);
     $element['time'] = [
       '#type' => 'select',
-      '#title' => t('First Event Starts At'),
+      '#title' => $this->t('First Event Starts At'),
       '#options' => $times,
       '#default_value' => $items[$delta]->time ?: $start_time,
       '#weight' => 3,
@@ -86,7 +89,7 @@ class ConsecutiveRecurringDateWidget extends DateRangeDefaultWidget {
 
     $element['end_time'] = [
       '#type' => 'select',
-      '#title' => t('Final Event Starts At'),
+      '#title' => $this->t('Final Event Starts At'),
       '#options' => $times,
       '#default_value' => $items[$delta]->end_time ?: $end_time,
       '#weight' => 4,
@@ -101,7 +104,7 @@ class ConsecutiveRecurringDateWidget extends DateRangeDefaultWidget {
 
     $element['duration'] = [
       '#type' => 'number',
-      '#title' => t('Event Duration'),
+      '#title' => $this->t('Event Duration'),
       '#default_value' => $items[$delta]->duration ?: 5,
       '#weight' => 5,
       '#ajax' => [
@@ -113,7 +116,7 @@ class ConsecutiveRecurringDateWidget extends DateRangeDefaultWidget {
 
     $element['duration_units'] = [
       '#type' => 'select',
-      '#title' => t('Event Duration'),
+      '#title' => $this->t('Event Duration'),
       '#options' => $units,
       '#default_value' => $items[$delta]->duration_units ?: 'minute',
       '#weight' => 6,
@@ -147,14 +150,14 @@ class ConsecutiveRecurringDateWidget extends DateRangeDefaultWidget {
 
     $element['buffer'] = [
       '#type' => 'number',
-      '#title' => t('Event Buffer'),
+      '#title' => $this->t('Event Buffer'),
       '#default_value' => $items[$delta]->buffer ?: 0,
       '#weight' => 7,
     ];
 
     $element['buffer_units'] = [
       '#type' => 'select',
-      '#title' => t('Event Buffer'),
+      '#title' => $this->t('Event Buffer'),
       '#options' => $units,
       '#default_value' => $items[$delta]->buffer_units ?: 'minute',
       '#weight' => 8,
@@ -197,7 +200,9 @@ class ConsecutiveRecurringDateWidget extends DateRangeDefaultWidget {
    */
   public function changeDuration(array $form, FormStateInterface $form_state) {
     $response = new AjaxResponse();
-    $form_id = $form_state->getBuildInfo()['form_id'] == 'eventseries_edit_form' ? 'eventseries-edit-form' : 'eventseries-add-form';
+    /* @var $entity \Drupal\recurring_events\Entity\EventSeries */
+    $entity = $form_state->getformObject()->getEntity();
+    $form_id = $form_state->getBuildInfo()['form_id'] == 'eventseries_' . $entity->bundle() . '_edit_form' ? 'eventseries-' . $entity->bundle() . '-edit-form' : 'eventseries-' . $entity->bundle() . '-add-form';
     $response->addCommand(new HtmlCommand('#' . $form_id, $form));
     return $response;
   }
@@ -209,7 +214,7 @@ class ConsecutiveRecurringDateWidget extends DateRangeDefaultWidget {
     $day_count = $time_count = $total = 0;
     $utc_timezone = new \DateTimeZone(DateTimeItemInterface::STORAGE_TIMEZONE);
     $form_data = ConsecutiveRecurringDate::convertFormConfigToArray($form_state);
-    if (!empty($form_data['start_date']) && !empty($form_data['end_date'])) {
+    if (!empty($form_data['start_date']) && !empty($form_data['end_date']) && !empty($form_data['duration'])) {
       $day_count = ConsecutiveRecurringDate::findDailyDatesBetweenDates($form_data['start_date'], $form_data['end_date'], TRUE);
       $time_parts = static::convertTimeTo24hourFormat($form_data['time']);
       if (!empty($time_parts)) {
@@ -251,4 +256,60 @@ class ConsecutiveRecurringDateWidget extends DateRangeDefaultWidget {
     }
   }
 
+  /**
+   * Element validate callback to ensure that widget values are valid.
+   *
+   * @param array $element
+   *   An associative array containing the properties and children of the
+   *   generic form element.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
+   * @param array $complete_form
+   *   The complete form structure.
+   */
+  public function validateForm(array &$element, FormStateInterface $form_state, array &$complete_form) {
+    $recur_type = $form_state->getValue('recur_type');
+    if ($recur_type[0]['value'] === 'consecutive_recurring_date') {
+      $values = $form_state->getValue('consecutive_recurring_date');
+      if (empty($values[0])) {
+        $form_state->setError($element, $this->t('Please configure the Consecutive Recurring Date settings'));
+      }
+      if (!empty($values[0])) {
+        $values = $values[0];
+
+        if (empty($values['value'])) {
+          $form_state->setError($element['value'], $this->t('Please enter a start date'));
+        }
+
+        if (empty($values['end_value'])) {
+          $form_state->setError($element['end_value'], $this->t('Please enter an end date'));
+        }
+
+        if (empty($values['time'])) {
+          $form_state->setError($element['time'], $this->t('Please enter a start time'));
+        }
+
+        if (empty($values['end_time'])) {
+          $form_state->setError($element['end_time'], $this->t('Please enter an end time'));
+        }
+
+        if (empty($values['duration']) || $values['duration'] < 1) {
+          $form_state->setError($element['duration'], $this->t('Please enter a duration greater than 0'));
+        }
+
+        if (empty($values['duration_units']) || !isset($complete_form['consecutive_recurring_date']['widget'][0]['duration_units']['#options'][$values['duration_units']])) {
+          $form_state->setError($element['duration_units'], $this->t('Please select a duration units value from the list'));
+        }
+
+        if (!isset($values['buffer']) || $values['buffer'] === '' || $values['buffer'] < 0) {
+          $form_state->setError($element['buffer'], $this->t('Please enter a buffer greater than or equal to 0'));
+        }
+
+        if (empty($values['buffer_units']) || !isset($complete_form['consecutive_recurring_date']['widget'][0]['buffer_units']['#options'][$values['buffer_units']])) {
+          $form_state->setError($element['buffer_units'], $this->t('Please select a buffer units value from the list'));
+        }
+      }
+    }
+  }
+
 }
diff --git a/src/Plugin/Field/FieldWidget/DailyRecurringDateWidget.php b/src/Plugin/Field/FieldWidget/DailyRecurringDateWidget.php
index 69a9c0270f97afdfe38ea2acfd1d81bf29960ce5..3b9864b37bbae754fcf22da59fecf3d45fa43cee 100644
--- a/src/Plugin/Field/FieldWidget/DailyRecurringDateWidget.php
+++ b/src/Plugin/Field/FieldWidget/DailyRecurringDateWidget.php
@@ -8,6 +8,7 @@ use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Datetime\DrupalDateTime;
 use Drupal\datetime\Plugin\Field\FieldType\DateTimeItemInterface;
 use Drupal\recurring_events\Plugin\RecurringEventsFieldTrait;
+use Drupal\Core\StringTranslation\StringTranslationTrait;
 
 /**
  * Plugin implementation of the 'daily recurring date' widget.
@@ -23,6 +24,7 @@ use Drupal\recurring_events\Plugin\RecurringEventsFieldTrait;
 class DailyRecurringDateWidget extends DateRangeDefaultWidget {
 
   use RecurringEventsFieldTrait;
+  use StringTranslationTrait;
 
   /**
    * {@inheritdoc}
@@ -36,15 +38,16 @@ class DailyRecurringDateWidget extends DateRangeDefaultWidget {
         ':input[name="recur_type"]' => ['value' => 'daily_recurring_date'],
       ],
     ];
+    $element['#element_validate'][] = [$this, 'validateForm'];
 
-    $element['value']['#title'] = t('Create Events Between');
+    $element['value']['#title'] = $this->t('Create Events Between');
     $element['value']['#weight'] = 1;
     $element['value']['#date_date_format'] = DateTimeItemInterface::DATE_STORAGE_FORMAT;
     $element['value']['#date_date_element'] = 'date';
     $element['value']['#date_time_format'] = '';
     $element['value']['#date_time_element'] = 'none';
 
-    $element['end_value']['#title'] = t('And');
+    $element['end_value']['#title'] = $this->t('And');
     $element['end_value']['#weight'] = 2;
     $element['end_value']['#date_date_format'] = DateTimeItemInterface::DATE_STORAGE_FORMAT;
     $element['end_value']['#date_date_element'] = 'date';
@@ -54,7 +57,7 @@ class DailyRecurringDateWidget extends DateRangeDefaultWidget {
     $times = $this->getTimeOptions();
     $element['time'] = [
       '#type' => 'select',
-      '#title' => t('Event Start Time'),
+      '#title' => $this->t('Event Start Time'),
       '#options' => $times,
       '#default_value' => $items[$delta]->time ?: '',
       '#weight' => 3,
@@ -63,7 +66,7 @@ class DailyRecurringDateWidget extends DateRangeDefaultWidget {
     $durations = $this->getDurationOptions();
     $element['duration'] = [
       '#type' => 'select',
-      '#title' => t('Event Duration'),
+      '#title' => $this->t('Event Duration'),
       '#options' => $durations,
       '#default_value' => $items[$delta]->duration ?: '',
       '#weight' => 4,
@@ -101,4 +104,44 @@ class DailyRecurringDateWidget extends DateRangeDefaultWidget {
     return $values;
   }
 
+  /**
+   * Element validate callback to ensure that widget values are valid.
+   *
+   * @param array $element
+   *   An associative array containing the properties and children of the
+   *   generic form element.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
+   * @param array $complete_form
+   *   The complete form structure.
+   */
+  public function validateForm(array &$element, FormStateInterface $form_state, array &$complete_form) {
+    $recur_type = $form_state->getValue('recur_type');
+    if ($recur_type[0]['value'] === 'daily_recurring_date') {
+      $values = $form_state->getValue('daily_recurring_date');
+      if (empty($values[0])) {
+        $form_state->setError($element, $this->t('Please configure the Daily Recurring Date settings'));
+      }
+      if (!empty($values[0])) {
+        $values = $values[0];
+
+        if (empty($values['value'])) {
+          $form_state->setError($element['value'], $this->t('Please enter a start date'));
+        }
+
+        if (empty($values['end_value'])) {
+          $form_state->setError($element['end_value'], $this->t('Please enter an end date'));
+        }
+
+        if (empty($values['time'])) {
+          $form_state->setError($element['time'], $this->t('Please enter a start time'));
+        }
+
+        if (empty($values['duration']) || !isset($complete_form['daily_recurring_date']['widget'][0]['duration']['#options'][$values['duration']])) {
+          $form_state->setError($element['duration'], $this->t('Please select a duration from the list'));
+        }
+      }
+    }
+  }
+
 }
diff --git a/src/Plugin/Field/FieldWidget/MonthlyRecurringDateWidget.php b/src/Plugin/Field/FieldWidget/MonthlyRecurringDateWidget.php
index 22bef8aa73e7c47f8f400e2a0d2f62812a36bb6c..a97f2634dacd5c2a8f6a0887ae25d1fd02df6be2 100644
--- a/src/Plugin/Field/FieldWidget/MonthlyRecurringDateWidget.php
+++ b/src/Plugin/Field/FieldWidget/MonthlyRecurringDateWidget.php
@@ -6,6 +6,7 @@ use Drupal\Core\Field\FieldItemListInterface;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Datetime\DrupalDateTime;
 use Drupal\datetime\Plugin\Field\FieldType\DateTimeItemInterface;
+use Drupal\Core\StringTranslation\StringTranslationTrait;
 
 /**
  * Plugin implementation of the 'monthly recurring date' widget.
@@ -20,6 +21,8 @@ use Drupal\datetime\Plugin\Field\FieldType\DateTimeItemInterface;
  */
 class MonthlyRecurringDateWidget extends WeeklyRecurringDateWidget {
 
+  use StringTranslationTrait;
+
   /**
    * {@inheritdoc}
    */
@@ -31,13 +34,14 @@ class MonthlyRecurringDateWidget extends WeeklyRecurringDateWidget {
         ':input[name="recur_type"]' => ['value' => 'monthly_recurring_date'],
       ],
     ];
+    $element['#element_validate'][] = [$this, 'validateForm'];
 
     $element['type'] = [
       '#type' => 'radios',
-      '#title' => t('Event Recurrence Schedule'),
+      '#title' => $this->t('Event Recurrence Schedule'),
       '#options' => [
-        'weekday' => t('Recur on Day of Week'),
-        'monthday' => t('Recur on Day of Month'),
+        'weekday' => $this->t('Recur on Day of Week'),
+        'monthday' => $this->t('Recur on Day of Month'),
       ],
       '#default_value' => $items[$delta]->type ?: '',
       '#weight' => 5,
@@ -45,13 +49,13 @@ class MonthlyRecurringDateWidget extends WeeklyRecurringDateWidget {
 
     $element['day_occurrence'] = [
       '#type' => 'checkboxes',
-      '#title' => t('Day Occurrence'),
+      '#title' => $this->t('Day Occurrence'),
       '#options' => [
-        'first' => t('First'),
-        'second' => t('Second'),
-        'third' => t('Third'),
-        'fourth' => t('Fourth'),
-        'last' => t('Last'),
+        'first' => $this->t('First'),
+        'second' => $this->t('Second'),
+        'third' => $this->t('Third'),
+        'fourth' => $this->t('Fourth'),
+        'last' => $this->t('Last'),
       ],
       '#default_value' => $items[$delta]->day_occurrence ? explode(',', $items[$delta]->day_occurrence) : [],
       '#states' => [
@@ -65,7 +69,7 @@ class MonthlyRecurringDateWidget extends WeeklyRecurringDateWidget {
     $days = $this->getDayOptions();
     $element['days'] = [
       '#type' => 'checkboxes',
-      '#title' => t('Days of the Week'),
+      '#title' => $this->t('Days of the Week'),
       '#options' => $days,
       '#default_value' => $items[$delta]->days ? explode(',', $items[$delta]->days) : [],
       '#states' => [
@@ -79,7 +83,7 @@ class MonthlyRecurringDateWidget extends WeeklyRecurringDateWidget {
     $month_days = $this->getMonthDayOptions();
     $element['day_of_month'] = [
       '#type' => 'checkboxes',
-      '#title' => t('Days of the Month'),
+      '#title' => $this->t('Days of the Month'),
       '#options' => $month_days,
       '#default_value' => $items[$delta]->day_of_month ? explode(',', $items[$delta]->day_of_month) : [],
       '#states' => [
@@ -136,11 +140,82 @@ class MonthlyRecurringDateWidget extends WeeklyRecurringDateWidget {
       $date->modify('+1 day');
     }
 
-    $days[-1] = t('Last');
+    $days[-1] = $this->t('Last');
 
     \Drupal::moduleHandler()->alter('recurring_events_month_days', $days);
 
     return $days;
   }
 
+  /**
+   * Element validate callback to ensure that widget values are valid.
+   *
+   * @param array $element
+   *   An associative array containing the properties and children of the
+   *   generic form element.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
+   * @param array $complete_form
+   *   The complete form structure.
+   */
+  public function validateForm(array &$element, FormStateInterface $form_state, array &$complete_form) {
+    $recur_type = $form_state->getValue('recur_type');
+    if ($recur_type[0]['value'] === 'monthly_recurring_date') {
+      $values = $form_state->getValue('monthly_recurring_date');
+      if (empty($values[0])) {
+        $form_state->setError($element, $this->t('Please configure the Monthly Recurring Date settings'));
+      }
+      if (!empty($values[0])) {
+        $values = $values[0];
+
+        if (empty($values['value'])) {
+          $form_state->setError($element['value'], $this->t('Please enter a start date'));
+        }
+
+        if (empty($values['end_value'])) {
+          $form_state->setError($element['end_value'], $this->t('Please enter an end date'));
+        }
+
+        if (empty($values['time'])) {
+          $form_state->setError($element['time'], $this->t('Please enter a start time'));
+        }
+
+        if (empty($values['duration']) || !isset($complete_form['monthly_recurring_date']['widget'][0]['duration']['#options'][$values['duration']])) {
+          $form_state->setError($element['duration'], $this->t('Please select a duration from the list'));
+        }
+
+        if (empty($values['type']) || !isset($complete_form['monthly_recurring_date']['widget'][0]['type']['#options'][$values['type']])) {
+          $form_state->setError($element['type'], $this->t('Please select an event recurrence schedule type from the list'));
+        }
+        else {
+          switch ($values['type']) {
+            case 'weekday':
+              $filtered_day_occurrences = array_filter($values['day_occurrence'], function ($value) {
+                return !empty($value);
+              });
+              if (empty($values['day_occurrence']) || empty($filtered_day_occurrences)) {
+                $form_state->setError($element['day_occurrence'], $this->t('Please select a day occurrence from the list'));
+              }
+              $filtered_days = array_filter($values['days'], function ($value) {
+                return !empty($value);
+              });
+              if (empty($values['days']) || empty($filtered_days)) {
+                $form_state->setError($element['days'], $this->t('Please select week days from the list'));
+              }
+              break;
+
+            case 'monthday':
+              $filtered_days = array_filter($values['day_of_month'], function ($value) {
+                return !empty($value);
+              });
+              if (empty($values['day_of_month']) || empty($filtered_days)) {
+                $form_state->setError($element['day_of_month'], $this->t('Please select days of the month from the list'));
+              }
+              break;
+          }
+        }
+      }
+    }
+  }
+
 }
diff --git a/src/Plugin/Field/FieldWidget/WeeklyRecurringDateWidget.php b/src/Plugin/Field/FieldWidget/WeeklyRecurringDateWidget.php
index 23dd15ffaee1a911bff6bf8d18785dfeb715f35a..f09b01c369eea30e98058c23143f9cdafced4d6b 100644
--- a/src/Plugin/Field/FieldWidget/WeeklyRecurringDateWidget.php
+++ b/src/Plugin/Field/FieldWidget/WeeklyRecurringDateWidget.php
@@ -5,6 +5,7 @@ namespace Drupal\recurring_events\Plugin\Field\FieldWidget;
 use Drupal\Core\Field\FieldItemListInterface;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Datetime\DrupalDateTime;
+use Drupal\Core\StringTranslation\StringTranslationTrait;
 
 /**
  * Plugin implementation of the 'weekly recurring date' widget.
@@ -19,6 +20,8 @@ use Drupal\Core\Datetime\DrupalDateTime;
  */
 class WeeklyRecurringDateWidget extends DailyRecurringDateWidget {
 
+  use StringTranslationTrait;
+
   /**
    * {@inheritdoc}
    */
@@ -31,11 +34,12 @@ class WeeklyRecurringDateWidget extends DailyRecurringDateWidget {
         ':input[name="recur_type"]' => ['value' => 'weekly_recurring_date'],
       ],
     ];
+    $element['#element_validate'][] = [$this, 'validateForm'];
 
     $days = $this->getDayOptions();
     $element['days'] = [
       '#type' => 'checkboxes',
-      '#title' => t('Days of the Week'),
+      '#title' => $this->t('Days of the Week'),
       '#options' => $days,
       '#default_value' => $items[$delta]->days ? explode(',', $items[$delta]->days) : [],
       '#weight' => 5,
@@ -99,4 +103,53 @@ class WeeklyRecurringDateWidget extends DailyRecurringDateWidget {
     return $days;
   }
 
+  /**
+   * Element validate callback to ensure that widget values are valid.
+   *
+   * @param array $element
+   *   An associative array containing the properties and children of the
+   *   generic form element.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
+   * @param array $complete_form
+   *   The complete form structure.
+   */
+  public function validateForm(array &$element, FormStateInterface $form_state, array &$complete_form) {
+    $recur_type = $form_state->getValue('recur_type');
+    if ($recur_type[0]['value'] === 'weekly_recurring_date') {
+      $values = $form_state->getValue('weekly_recurring_date');
+      if (empty($values[0])) {
+        $form_state->setError($element, $this->t('Please configure the Weekly Recurring Date settings'));
+      }
+      if (!empty($values[0])) {
+        $values = $values[0];
+
+        if (empty($values['value'])) {
+          $form_state->setError($element['value'], $this->t('Please enter a start date'));
+        }
+
+        if (empty($values['end_value'])) {
+          $form_state->setError($element['end_value'], $this->t('Please enter an end date'));
+        }
+
+        if (empty($values['time'])) {
+          $form_state->setError($element['time'], $this->t('Please enter a start time'));
+        }
+
+        if (empty($values['duration']) || !isset($complete_form['weekly_recurring_date']['widget'][0]['duration']['#options'][$values['duration']])) {
+          $form_state->setError($element['duration'], $this->t('Please select a duration from the list'));
+        }
+
+        $filtered_days = array_filter($values['days'], function ($value) {
+          return !empty($value);
+        });
+
+        if (empty($values['days']) || empty($filtered_days)) {
+          $form_state->setError($element['days'], $this->t('Please select week days from the list'));
+        }
+
+      }
+    }
+  }
+
 }
diff --git a/src/Plugin/FieldInheritance/BooleanFieldInheritancePlugin.php b/src/Plugin/FieldInheritance/BooleanFieldInheritancePlugin.php
deleted file mode 100644
index 772417c63162a8cced8294a2a8ae70f34174774e..0000000000000000000000000000000000000000
--- a/src/Plugin/FieldInheritance/BooleanFieldInheritancePlugin.php
+++ /dev/null
@@ -1,19 +0,0 @@
-<?php
-
-namespace Drupal\recurring_events\Plugin\FieldInheritance;
-
-use Drupal\recurring_events\FieldInheritancePluginInterface;
-
-/**
- * Boolean Inheritance plugin.
- *
- * @FieldInheritance(
- *   id = "boolean_inheritance",
- *   name = @Translation("Boolean Field Inheritance"),
- *   types = {
- *     "boolean"
- *   }
- * )
- */
-class BooleanFieldInheritancePlugin extends FieldInheritancePluginBase implements FieldInheritancePluginInterface {
-}
diff --git a/src/Plugin/FieldInheritance/DateFieldInheritancePlugin.php b/src/Plugin/FieldInheritance/DateFieldInheritancePlugin.php
deleted file mode 100644
index 98ab60ceb857cf9977391f88f32a954e8c30762e..0000000000000000000000000000000000000000
--- a/src/Plugin/FieldInheritance/DateFieldInheritancePlugin.php
+++ /dev/null
@@ -1,20 +0,0 @@
-<?php
-
-namespace Drupal\recurring_events\Plugin\FieldInheritance;
-
-use Drupal\recurring_events\FieldInheritancePluginInterface;
-
-/**
- * Date Inheritance plugin.
- *
- * @FieldInheritance(
- *   id = "date_inheritance",
- *   name = @Translation("Date Field Inheritance"),
- *   types = {
- *     "datetime",
- *     "daterange",
- *   }
- * )
- */
-class DateFieldInheritancePlugin extends FieldInheritancePluginBase implements FieldInheritancePluginInterface {
-}
diff --git a/src/Plugin/FieldInheritance/EmailFieldInheritancePlugin.php b/src/Plugin/FieldInheritance/EmailFieldInheritancePlugin.php
deleted file mode 100644
index be99bb30cccc2f3a22bf939556180bd9687bc56c..0000000000000000000000000000000000000000
--- a/src/Plugin/FieldInheritance/EmailFieldInheritancePlugin.php
+++ /dev/null
@@ -1,19 +0,0 @@
-<?php
-
-namespace Drupal\recurring_events\Plugin\FieldInheritance;
-
-use Drupal\recurring_events\FieldInheritancePluginInterface;
-
-/**
- * Email Inheritance plugin.
- *
- * @FieldInheritance(
- *   id = "email_inheritance",
- *   name = @Translation("Email Field Inheritance"),
- *   types = {
- *     "email"
- *   }
- * )
- */
-class EmailFieldInheritancePlugin extends FieldInheritancePluginBase implements FieldInheritancePluginInterface {
-}
diff --git a/src/Plugin/FieldInheritance/EntityReferenceFieldInheritancePlugin.php b/src/Plugin/FieldInheritance/EntityReferenceFieldInheritancePlugin.php
deleted file mode 100644
index 6084798f1eb5a0587772ee246d1d1c3522ec4807..0000000000000000000000000000000000000000
--- a/src/Plugin/FieldInheritance/EntityReferenceFieldInheritancePlugin.php
+++ /dev/null
@@ -1,22 +0,0 @@
-<?php
-
-namespace Drupal\recurring_events\Plugin\FieldInheritance;
-
-use Drupal\recurring_events\FieldInheritancePluginInterface;
-
-/**
- * Entity Reference Inheritance plugin.
- *
- * @FieldInheritance(
- *   id = "entity_reference_inheritance",
- *   name = @Translation("Entity Reference Field Inheritance"),
- *   types = {
- *     "entity_reference",
- *     "image",
- *     "file",
- *     "webform"
- *   }
- * )
- */
-class EntityReferenceFieldInheritancePlugin extends FieldInheritancePluginBase implements FieldInheritancePluginInterface {
-}
diff --git a/src/Plugin/FieldInheritance/FieldInheritancePluginBase.php b/src/Plugin/FieldInheritance/FieldInheritancePluginBase.php
deleted file mode 100644
index 984276d16e74f3f61e8f1aa365ffc8e63b3b63cb..0000000000000000000000000000000000000000
--- a/src/Plugin/FieldInheritance/FieldInheritancePluginBase.php
+++ /dev/null
@@ -1,287 +0,0 @@
-<?php
-
-namespace Drupal\recurring_events\Plugin\FieldInheritance;
-
-use Drupal\Component\Plugin\PluginBase;
-use Symfony\Component\DependencyInjection\ContainerInterface;
-use Drupal\recurring_events\FieldInheritancePluginInterface;
-use Drupal\Core\Language\LanguageManagerInterface;
-use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
-
-/**
- * Abstract class FieldInheritancePluginBase.
- */
-abstract class FieldInheritancePluginBase extends PluginBase implements FieldInheritancePluginInterface, ContainerFactoryPluginInterface {
-
-  /**
-   * The entity.
-   *
-   * @var \Drupal\Core\Entity\EntityInterface
-   */
-  protected $entity;
-
-  /**
-   * The method used to inherit.
-   *
-   * @var string
-   */
-  protected $method;
-
-  /**
-   * The source field used to inherit.
-   *
-   * @var string
-   */
-  protected $sourceField;
-
-  /**
-   * The entity field used to inherit.
-   *
-   * @var string
-   */
-  protected $entityField;
-
-  /**
-   * The language manager service.
-   *
-   * @var \Drupal\Core\Language\LanguageManagerInterface
-   */
-  protected $languageManager;
-
-  /**
-   * The current language code.
-   *
-   * @var string
-   */
-  protected $langCode;
-
-  /**
-   * Constructs a FieldInheritancePluginBase object.
-   *
-   * @param array $configuration
-   *   The plugin configuration.
-   * @param string $plugin_id
-   *   The plugin ID.
-   * @param mixed $plugin_definition
-   *   The plugin definition.
-   * @param Drupal\Core\Language\LanguageManagerInterface $language_manager
-   *   The language manager service.
-   */
-  public function __construct(array $configuration, $plugin_id, $plugin_definition, LanguageManagerInterface $language_manager) {
-    parent::__construct($configuration, $plugin_id, $plugin_definition);
-    $this->entity = $configuration['entity'];
-    $this->method = $configuration['method'];
-    $this->sourceField = $configuration['source field'];
-    if (!empty($configuration['entity field'])) {
-      $this->entityField = $configuration['entity field'];
-    }
-    $this->languageManager = $language_manager;
-    $this->langCode = $this->languageManager->getCurrentLanguage()->getId();
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
-    return new static(
-      $configuration,
-      $plugin_id,
-      $plugin_definition,
-      $container->get('language_manager')
-    );
-  }
-
-  /**
-   * Get the configuration method.
-   */
-  public function getMethod() {
-    return $this->method;
-  }
-
-  /**
-   * Get the configuration source field.
-   */
-  public function getSourceField() {
-    return $this->sourceField;
-  }
-
-  /**
-   * Get the configuration entity field.
-   */
-  public function getEntityField() {
-    return $this->entityField;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function computeValue() {
-    $this->validateArguments();
-    $method = $this->getMethod();
-
-    $value = '';
-    switch ($method) {
-      case 'inherit':
-        $value = $this->inheritData();
-        break;
-
-      case 'prepend':
-        $value = $this->prependData();
-        break;
-
-      case 'append':
-        $value = $this->appendData();
-        break;
-
-      case 'fallback':
-        $value = $this->fallbackData();
-        break;
-    }
-    return $value;
-  }
-
-  /**
-   * Retrieve inherited data.
-   *
-   * @return string
-   *   The inherited data.
-   */
-  protected function inheritData() {
-    $series = $this->getEventSeries();
-    if ($series === FALSE) {
-      return [];
-    }
-    return $series->{$this->getSourceField()}->getValue() ?? '';
-  }
-
-  /**
-   * Retrieve prepended data.
-   *
-   * @return string
-   *   The prepended data.
-   */
-  protected function prependData() {
-    $series = $this->getEventSeries();
-    $instance = $this->getEventInstance();
-    $values = [];
-
-    if ($series === FALSE) {
-      return $values;
-    }
-
-    if (!empty($instance->{$this->getEntityField()}->getValue())) {
-      $values = array_merge($values, $instance->{$this->getEntityField()}->getValue());
-    }
-    if (!empty($series->{$this->getSourceField()}->getValue())) {
-      $values = array_merge($values, $series->{$this->getSourceField()}->getValue());
-    }
-    return $values;
-  }
-
-  /**
-   * Retrieve appended data.
-   *
-   * @return string
-   *   The appended data.
-   */
-  protected function appendData() {
-    $series = $this->getEventSeries();
-    $instance = $this->getEventInstance();
-    $values = [];
-
-    if ($series === FALSE) {
-      return $values;
-    }
-
-    if (!empty($series->{$this->getSourceField()}->getValue())) {
-      $values = array_merge($values, $series->{$this->getSourceField()}->getValue());
-    }
-    if (!empty($instance->{$this->getEntityField()}->getValue())) {
-      $values = array_merge($values, $instance->{$this->getEntityField()}->getValue());
-    }
-    return $values;
-  }
-
-  /**
-   * Retrieve fallback data.
-   *
-   * @return string
-   *   The fallback data.
-   */
-  protected function fallbackData() {
-    $series = $this->getEventSeries();
-    $instance = $this->getEventInstance();
-    $values = [];
-
-    if ($series === FALSE) {
-      return $values;
-    }
-
-    if (!empty($instance->{$this->getEntityField()}->getValue())) {
-      $values = $instance->{$this->getEntityField()}->getValue();
-    }
-    elseif (!empty($series->{$this->getSourceField()}->getValue())) {
-      $values = $series->{$this->getSourceField()}->getValue();
-    }
-    return $values;
-  }
-
-  /**
-   * Validate the configuration arguments of the plugin.
-   */
-  protected function validateArguments() {
-    if (empty($this->getMethod())) {
-      throw new \InvalidArgumentException("The definition's 'method' key must be set to inherit data.");
-    }
-
-    if (empty($this->getSourceField())) {
-      throw new \InvalidArgumentException("The definition's 'source field' key must be set to inherit data.");
-    }
-
-    $method = $this->getMethod();
-    $entity_field_methods = [
-      'prepend',
-      'append',
-      'fallback',
-    ];
-
-    if (array_search($method, $entity_field_methods)) {
-      if (empty($this->getEntityField())) {
-        throw new \InvalidArgumentException("The definition's 'entity field' key must be set to prepend, append, or fallback to series data.");
-      }
-    }
-
-    return TRUE;
-  }
-
-  /**
-   * Get the translated eventseries entity.
-   *
-   * @return Drupal\Core\Entity\EntityInterface|bool
-   *   The translated eventseries entity, or FALSE.
-   */
-  protected function getEventSeries() {
-    $series = $this->entity->getEventSeries();
-    if (empty($series)) {
-      return FALSE;
-    }
-    if ($series->hasTranslation($this->langCode)) {
-      return $series->getTranslation($this->langCode);
-    }
-    return $series;
-  }
-
-  /**
-   * Get the translated eventinstance entity.
-   *
-   * @return Drupal\Core\Entity\EntityInterface
-   *   The translated eventinstance entity.
-   */
-  protected function getEventInstance() {
-    if ($this->entity->hasTranslation($this->langCode)) {
-      return $this->entity->getTranslation($this->langCode);
-    }
-    return $this->entity;
-  }
-
-}
diff --git a/src/Plugin/FieldInheritance/NumberFieldInheritancePlugin.php b/src/Plugin/FieldInheritance/NumberFieldInheritancePlugin.php
deleted file mode 100644
index 1457b90891ac972f202e9415c3c5f352202a9644..0000000000000000000000000000000000000000
--- a/src/Plugin/FieldInheritance/NumberFieldInheritancePlugin.php
+++ /dev/null
@@ -1,23 +0,0 @@
-<?php
-
-namespace Drupal\recurring_events\Plugin\FieldInheritance;
-
-use Drupal\recurring_events\FieldInheritancePluginInterface;
-
-/**
- * Number Inheritance plugin.
- *
- * @FieldInheritance(
- *   id = "number_inheritance",
- *   name = @Translation("Number Field Inheritance"),
- *   types = {
- *     "decimal",
- *     "float",
- *     "integer",
- *     "list_float",
- *     "list_integer"
- *   }
- * )
- */
-class NumberFieldInheritancePlugin extends FieldInheritancePluginBase implements FieldInheritancePluginInterface {
-}
diff --git a/src/Plugin/FieldInheritance/StringFieldInheritancePlugin.php b/src/Plugin/FieldInheritance/StringFieldInheritancePlugin.php
deleted file mode 100644
index cd71519ebd21f98186a16e9a9b7261cf0385fea1..0000000000000000000000000000000000000000
--- a/src/Plugin/FieldInheritance/StringFieldInheritancePlugin.php
+++ /dev/null
@@ -1,20 +0,0 @@
-<?php
-
-namespace Drupal\recurring_events\Plugin\FieldInheritance;
-
-use Drupal\recurring_events\FieldInheritancePluginInterface;
-
-/**
- * String Inheritance plugin.
- *
- * @FieldInheritance(
- *   id = "string_inheritance",
- *   name = @Translation("String Field Inheritance"),
- *   types = {
- *     "string",
- *     "string_long"
- *   }
- * )
- */
-class StringFieldInheritancePlugin extends FieldInheritancePluginBase implements FieldInheritancePluginInterface {
-}
diff --git a/src/Plugin/FieldInheritance/TextFieldInheritancePlugin.php b/src/Plugin/FieldInheritance/TextFieldInheritancePlugin.php
deleted file mode 100644
index ff12b078a2ee03fe95f95c90eba1804461301b26..0000000000000000000000000000000000000000
--- a/src/Plugin/FieldInheritance/TextFieldInheritancePlugin.php
+++ /dev/null
@@ -1,24 +0,0 @@
-<?php
-
-namespace Drupal\recurring_events\Plugin\FieldInheritance;
-
-use Drupal\recurring_events\FieldInheritancePluginInterface;
-
-/**
- * Text Inheritance plugin.
- *
- * @FieldInheritance(
- *   id = "text_inheritance",
- *   name = @Translation("Text Field Inheritance"),
- *   types = {
- *     "text",
- *     "text_long",
- *     "text_with_summary",
- *     "string",
- *     "string_long",
- *     "list_string"
- *   }
- * )
- */
-class TextFieldInheritancePlugin extends FieldInheritancePluginBase implements FieldInheritancePluginInterface {
-}
diff --git a/src/Plugin/views/field/InheritedField.php b/src/Plugin/views/field/InheritedField.php
deleted file mode 100644
index 00c7107a78785919b0e00c8d8fd16f4094d1976b..0000000000000000000000000000000000000000
--- a/src/Plugin/views/field/InheritedField.php
+++ /dev/null
@@ -1,16 +0,0 @@
-<?php
-
-namespace Drupal\recurring_events\Plugin\views\field;
-
-use Drupal\views\Plugin\views\field\EntityField;
-
-/**
- * Field handler to show the inherited field data.
- *
- * @ingroup views_field_handlers
- *
- * @ViewsField("inherited_field")
- */
-class InheritedField extends EntityField {
-
-}
diff --git a/templates/eventseries-add-list.html.twig b/templates/eventseries-add-list.html.twig
new file mode 100644
index 0000000000000000000000000000000000000000..e2d7ad38cf2e93e4cc267502f86849b2c7b5285a
--- /dev/null
+++ b/templates/eventseries-add-list.html.twig
@@ -0,0 +1,32 @@
+{#
+/**
+ * @file
+ * Default theme implementation to list eventseries types available.
+ *
+ * This list is displayed on the Add events page.
+ *
+ * Available variables:
+ * - types: A list of eventseries types, each with the following properties:
+ *   - add_link: Link to create an event of this type.
+ *   - description: Description of this type of eventseries.
+ *
+ * @see template_preprocess_eventseries_add_list()
+ *
+ * @ingroup themeable
+ */
+#}
+{% if types is not empty %}
+  <dl>
+    {% for type in types %}
+      <dt>{{ type.add_link }}</dt>
+      <dd>{{ type.description }}</dd>
+    {% endfor %}
+  </dl>
+{% else %}
+  <p>
+    {% set create_content = path('eventseries_type.add') %}
+    {% trans %}
+      You have not created any event types yet. Go to the <a href="{{ create_content }}">eventseries type creation page</a> to add a new eventseries type.
+    {% endtrans %}
+  </p>
+{% endif %}
diff --git a/tests/src/Functional/LoadTest.php b/tests/src/Functional/LoadTest.php
index db0f41edc534848e5fd25efe29500c884f7c92b2..2de25fa7344a4b0de6ee1012c2ac985d3663ac30 100644
--- a/tests/src/Functional/LoadTest.php
+++ b/tests/src/Functional/LoadTest.php
@@ -26,6 +26,13 @@ class LoadTest extends BrowserTestBase {
    */
   protected $user;
 
+  /**
+   * Set the default theme to use.
+   *
+   * @var \string
+   */
+  protected $defaultTheme = 'stark';
+
   /**
    * {@inheritdoc}
    */