diff --git a/modules/webform_demo/webform_demo_event_registration/config/install/webform.webform.demo_event_registration.yml b/modules/webform_demo/webform_demo_event_registration/config/install/webform.webform.demo_event_registration.yml
index 1aab15f1..47d47fc5 100644
--- a/modules/webform_demo/webform_demo_event_registration/config/install/webform.webform.demo_event_registration.yml
+++ b/modules/webform_demo/webform_demo_event_registration/config/install/webform.webform.demo_event_registration.yml
@@ -15,17 +15,6 @@ title: 'Demo: Event Registration'
 description: 'A demonstration of an event registration form.'
 category: Demo
 elements: |
-  event_information:
-    '#type': fieldset
-    '#title': 'Event Information'
-    event_title:
-      '#type': webform_computed_token
-      '#title': 'Event Title'
-      '#value': '[webform_submission:node:title]'
-    event_date:
-      '#type': webform_computed_token
-      '#title': 'Event Date'
-      '#value': '[webform_submission:node:field_webform_demo_event_date:date:short]'
   information:
     '#title': 'Your Information'
     '#type': fieldset
@@ -41,10 +30,10 @@ elements: |
       '#type': email
       '#title': Email
       '#required': true
-  actions:
-    '#type': webform_actions
-    '#title': 'Submit button(s)'
-    '#submit__label': Register
+    actions:
+      '#type': webform_actions
+      '#title': 'Submit button(s)'
+      '#submit__label': 'Register'
 css: ''
 javascript: ''
 settings:
diff --git a/modules/webform_node/webform_node.routing.yml b/modules/webform_node/webform_node.routing.yml
index 8eb2a394..990ea2bf 100644
--- a/modules/webform_node/webform_node.routing.yml
+++ b/modules/webform_node/webform_node.routing.yml
@@ -66,7 +66,7 @@ entity.node.webform.user.submission:
 entity.node.webform.user.submission.edit:
   path: '/node/{node}/webform/submissions/{webform_submission}/edit'
   defaults:
-    _entity_form: 'webform_submission.edit'
+    _entity_form: 'webform_submission.default'
     _title_callback: 'Drupal\webform\Controller\WebformSubmissionController::title'
     operation: webform_submission_edit
     entity_access: 'webform_submission.update'
diff --git a/src/Controller/WebformTestController.php b/src/Controller/WebformTestController.php
index d2684171..0d2654fb 100644
--- a/src/Controller/WebformTestController.php
+++ b/src/Controller/WebformTestController.php
@@ -73,14 +73,13 @@ class WebformTestController extends ControllerBase implements ContainerInjection
       $values['entity_id'] = $source_entity->id();
     }
 
-    // @todo Determine why we are checking for the webform id as querystring parameter.
     if ($request->query->get('webform_id') == $webform->id()) {
       return $webform->getSubmissionForm($values);
     }
 
     // Generate date.
     $values['data'] = $this->generate->getData($webform);
-    return $webform->getSubmissionForm($values, 'test');
+    return $webform->getSubmissionForm($values);
   }
 
   /**
diff --git a/src/Entity/WebformSubmission.php b/src/Entity/WebformSubmission.php
index 95ca7480..bd6f9ec1 100644
--- a/src/Entity/WebformSubmission.php
+++ b/src/Entity/WebformSubmission.php
@@ -34,9 +34,6 @@ use Drupal\webform\WebformSubmissionInterface;
  *     "access" = "Drupal\webform\WebformSubmissionAccessControlHandler",
  *     "form" = {
  *       "default" = "Drupal\webform\WebformSubmissionForm",
- *       "add" = "Drupal\webform\WebformSubmissionForm",
- *       "edit" = "Drupal\webform\WebformSubmissionForm",
- *       "test" = "Drupal\webform\WebformSubmissionForm",
  *       "notes" = "Drupal\webform\WebformSubmissionNotesForm",
  *       "duplicate" = "Drupal\webform\WebformSubmissionDuplicateForm",
  *       "delete" = "Drupal\webform\Form\WebformSubmissionDeleteForm",
diff --git a/src/Plugin/WebformElementBase.php b/src/Plugin/WebformElementBase.php
index 8ba1692a..921362be 100644
--- a/src/Plugin/WebformElementBase.php
+++ b/src/Plugin/WebformElementBase.php
@@ -1552,6 +1552,24 @@ class WebformElementBase extends PluginBase implements WebformElementInterface {
     return [];
   }
 
+  /**
+   * Get an element's (sub)input selector value.
+   *
+   * @param sring $selector
+   *   CSS :input selector.
+   * @param array $element
+   *   An element.
+   * @param \Drupal\webform\WebformSubmissionInterface $webform_submission
+   *   A webform submission.
+   *
+   * @return mixed
+   *   The element input's value.
+   */
+  public function getElementSelectorInputValue($selector, array $element, WebformSubmissionInterface $webform_submission) {
+    $element['#format'] = 'raw';
+    return $this->getValue($element, $webform_submission);
+  }
+
   /****************************************************************************/
   // Operation methods.
   /****************************************************************************/
diff --git a/src/Plugin/WebformElementInterface.php b/src/Plugin/WebformElementInterface.php
index b2081a85..bba5315e 100644
--- a/src/Plugin/WebformElementInterface.php
+++ b/src/Plugin/WebformElementInterface.php
@@ -655,6 +655,21 @@ interface WebformElementInterface extends PluginInspectionInterface, PluginFormI
    */
   public function getElementSelectorOptions(array $element);
 
+  /**
+   * Get an element's (sub)input selector value.
+   *
+   * @param sring $selector
+   *   CSS :input selector.
+   * @param array $element
+   *   An element.
+   * @param \Drupal\webform\WebformSubmissionInterface $webform_submission
+   *   A webform submission.
+   *
+   * @return mixed
+   *   The element input's value.
+   */
+  public function getElementSelectorInputValue($selector, array $element, WebformSubmissionInterface $webform_submission);
+
   /****************************************************************************/
   // Operation methods.
   /****************************************************************************/
diff --git a/src/WebformAddonsManager.php b/src/WebformAddonsManager.php
index 63b19ae3..0d3921fe 100644
--- a/src/WebformAddonsManager.php
+++ b/src/WebformAddonsManager.php
@@ -136,7 +136,7 @@ class WebformAddonsManager implements WebformAddonsManagerInterface {
         '#markup' => '<img' . $img_attributes . ' />',
       ],
       [
-        '#markup' => $this->t('The Lingotek-Inside Drupal Module integrates a translation management system (TMS) directly into Drupal, thus allowing the Drupal community to use professional-grade translation technologies (e.g. machine translation, translation memory, CAT tool) without ever having to leave the comfort of the Drupal environment.'),
+        '#markup' => $this->t('The Lingotek-Inside Drupal Module is the only Drupal module to integrate a translation management system (TMS) directly into Drupal, thus allowing the Drupal community to use professional-grade translation technologies (e.g. machine translation, translation memory, CAT tool) without ever having to leave the comfort of the Drupal environment.'),
         '#prefix' => '<p>',
         '#suffix' => '<p>',
       ],
diff --git a/src/WebformRequestInterface.php b/src/WebformRequestInterface.php
index cd75e96f..36c32d7a 100644
--- a/src/WebformRequestInterface.php
+++ b/src/WebformRequestInterface.php
@@ -4,9 +4,6 @@ namespace Drupal\webform;
 
 use Drupal\Core\Entity\EntityInterface;
 
-/**
- * Helper class webform entity methods.
- */
 /**
  * Provides an interface defining a webform request handler.
  */
diff --git a/src/WebformStatesValidator.php b/src/WebformStatesValidator.php
new file mode 100644
index 00000000..76f02b19
--- /dev/null
+++ b/src/WebformStatesValidator.php
@@ -0,0 +1,224 @@
+<?php
+
+namespace Drupal\webform;
+
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Render\Element;
+use Drupal\Core\StringTranslation\StringTranslationTrait;
+use Drupal\webform\Plugin\WebformElementManagerInterface;
+
+/**
+ * Webform states validator.
+ *
+ * @see \Drupal\webform\Element\WebformElementStates
+ * @see drupal_process_states()
+ */
+class WebformStatesValidator implements WebformStatesValidatorInterface {
+
+  use StringTranslationTrait;
+
+  /**
+   * The webform element manager.
+   *
+   * @var \Drupal\webform\Plugin\WebformElementManagerInterface
+   */
+  protected $elementManager;
+
+  /**
+   * Constructs a WebformStatesValidator object.
+   *
+   * @param \Drupal\webform\Plugin\WebformElementManagerInterface $element_manager
+   *   The webform element manager.
+   */
+  public function __construct(WebformElementManagerInterface $element_manager) {
+    $this->elementManager = $element_manager;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function validateForm(array &$form, FormStateInterface $form_state)  {
+    /** @var \Drupal\webform\WebformSubmissionForm $form_object */
+    $form_object = $form_state->getFormObject();
+
+    /** @var \Drupal\webform\WebformSubmissionInterface $webform_submission */
+    $webform_submission = $form_object->getEntity();
+    $webform_submission->getWebform();
+
+    // Get visible form elements with #states.
+    $dependents = $this->getVisibleElementsWithStates($form);
+
+    foreach ($dependents as $key => $dependent) {
+      foreach ($dependent['#states'] as $state => $conditions) {
+        if (!in_array($state,  ['required', 'optional'])) {
+          continue;
+        }
+
+        $is_required = $this->validateConditions($conditions, $webform_submission);
+        if ($state == 'optional') {
+          $is_required = !$is_required;
+        }
+
+        if ($is_required && empty($form_state->getValue($key))) {
+          $this->setRequiredError($dependent, $form_state);
+        }
+      }
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function validateConditions(array $conditions, WebformSubmissionInterface $webform_submission) {
+    /** @var \Drupal\webform\Plugin\WebformElementManagerInterface $element_manager */
+    $element_manager = \Drupal::service('plugin.manager.webform.element');
+
+    $condition_logic = 'and';
+    $condition_results = [];
+    foreach ($conditions as $index => $value) {
+      if (is_string($value) && in_array($value, ['and', 'or', 'xor'])) {
+        $condition_logic = $value;
+        continue;
+      }
+      elseif (is_int($index)) {
+        $selector = key($value);
+        $condition = $value[$selector];
+      }
+      else {
+        $selector = $index;
+        $condition = $value;
+      }
+
+      // Ignore invalid selector and return TRUE.
+      if (!preg_match('/\:input\[name="([^"]+)"\]/', $selector, $match)) {
+        return TRUE;
+      }
+
+      $input_name = $match[1];
+      list($element_key) = explode('][', $input_name);
+      $element = $webform_submission->getWebform()->getElement($element_key);
+
+      // Ignore missing dependee element and return TRUE.
+      if (!$element) {
+        return TRUE;
+      }
+
+      $element_handler = $element_manager->getElementInstance($element);
+      $element_value = $element_handler->getElementSelectorInputValue($selector, $element, $webform_submission);
+      $trigger_state = key($condition);
+      $trigger_value = $condition[$trigger_state];
+
+      // Process triggers (aka remote conditions).
+      // @see \Drupal\webform\Element\WebformElementStates::processWebformStates
+      switch ($trigger_state) {
+        case 'empty':
+          $condition_results[$selector] = (empty($element_value) === (boolean) $trigger_value);
+          break;
+
+        case 'filled';
+          $condition_results[$selector] = (!empty($element_value) === (boolean) $trigger_value);
+          break;
+
+        case 'checked':
+          $condition_results[$selector] = ((boolean) $element_value === (boolean) $trigger_value);
+          break;
+
+        case 'unchecked';
+          $element_value = (boolean) $element_value;
+          $condition_results[$selector] = !((boolean) $element_value === (boolean) $trigger_value);
+          break;
+
+        case 'value':
+          $condition_results[$selector] = ($element_value == $trigger_value);
+          break;
+
+        case '!value':
+          $condition_results[$selector] = !($element_value == $trigger_value);
+          break;
+      }
+    }
+
+    $conditions_sum = array_sum($condition_results);
+    $conditions_total = count($condition_results);
+    switch ($condition_logic) {
+      case 'xor':
+        return ($conditions_sum && $conditions_sum !== $conditions_total);
+
+      case 'and':
+        return ($conditions_sum === $conditions_total);
+
+      case 'or':
+        return (boolean) $conditions_sum;
+    }
+  }
+
+  /****************************************************************************/
+  // Validation methods.
+  /****************************************************************************/
+
+  /**
+   * Set required validation message for an element.
+   *
+   * @param array $element
+   *   An element.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
+   */
+  protected function setRequiredError(array $element, FormStateInterface $form_state) {
+    if (isset($element['#required_error'])) {
+      $form_state->setError($element, $element['#required_error']);
+    }
+    elseif (isset($element['#title'])) {
+      $form_state->setError($element, $this->t('@name field is required.', ['@name' => $element['#title']]));
+    }
+    else {
+      $form_state->setError($element);
+    }
+  }
+
+  /****************************************************************************/
+  // Element methods.
+  /****************************************************************************/
+
+  /**
+   * Get visible elements with #states property from a form.
+   *
+   * @param array $form
+   *   An associative array containing the structure of the form.
+   *
+   * @return array
+   *   Visible elements with #states property
+   */
+  protected function getVisibleElementsWithStates(array $form) {
+    $elements = [];
+    $this->getVisibleElementWithStatesRecursive($elements, $form);
+    return $elements;
+  }
+
+  /**
+   * Recurse through a form and get visible elements with #states property.
+   *
+   * @param array $elements
+   *   Visible elements with #states property
+   * @param array $form
+   *   An associative array containing the structure of the form.
+   */
+  protected function getVisibleElementWithStatesRecursive(array &$elements, array $form) {
+    foreach ($form as $key => &$element) {
+      if (Element::property($key) || !is_array($element)) {
+        continue;
+      }
+
+      if (isset($element['#access']) && $element['#access'] === FALSE) {
+        continue;
+      }
+
+      if (isset($element['#states'])) {
+        $elements[$key] = $element;
+      }
+
+      $this->getVisibleElementWithStatesRecursive($elements, $element);
+    }
+  }
+
+}
\ No newline at end of file
diff --git a/src/WebformStatesValidatorInterface.php b/src/WebformStatesValidatorInterface.php
new file mode 100644
index 00000000..f8cc8f9e
--- /dev/null
+++ b/src/WebformStatesValidatorInterface.php
@@ -0,0 +1,37 @@
+<?php
+
+namespace Drupal\webform;
+
+use Drupal\Core\Form\FormStateInterface;
+
+/**
+ * Provides an interface defining a webform states validator.
+ */
+interface WebformStatesValidatorInterface {
+
+  /**
+   * Validate form #states for visible elements.
+   *
+   * @param array $form
+   *   An associative array containing the structure of the form.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
+   */
+  public function validateForm(array &$form, FormStateInterface $form_state);
+
+  /**
+   * Validate #state conditions.
+   *
+   * @param array $conditions
+   *   An associative array containing conditions.
+   * @param \Drupal\webform\WebformSubmissionInterface $webform_submission
+   *   A webform submission.
+   *
+   * @return bool
+   *   TRUE if conditions validate.
+   *
+   * @see drupal_process_states()
+   */
+  public function validateConditions(array $conditions, WebformSubmissionInterface $webform_submission);
+
+}
\ No newline at end of file
diff --git a/src/WebformSubmissionForm.php b/src/WebformSubmissionForm.php
index cf0ca121..6e67b488 100644
--- a/src/WebformSubmissionForm.php
+++ b/src/WebformSubmissionForm.php
@@ -115,6 +115,13 @@ class WebformSubmissionForm extends ContentEntityForm {
    */
   protected $tokenManager;
 
+  /**
+   * The webform (server-side) #states validator.
+   *
+   * @var \Drupal\webform\WebformStatesValidator
+   */
+  protected $statesValidator;
+
   /**
    * The webform settings.
    *
@@ -158,7 +165,7 @@ class WebformSubmissionForm extends ContentEntityForm {
    * @param \Drupal\webform\WebformTokenManagerInterface $token_manager
    *   The webform token manager.
    */
-  public function __construct(EntityManagerInterface $entity_manager, RendererInterface $renderer, AliasManagerInterface $alias_manager, PathValidatorInterface $path_validator, WebformRequestInterface $request_handler, WebformElementManagerInterface $element_manager, WebformThirdPartySettingsManagerInterface $third_party_settings_manager, WebformMessageManagerInterface $message_manager, WebformTokenManagerInterface $token_manager) {
+  public function __construct(EntityManagerInterface $entity_manager, RendererInterface $renderer, AliasManagerInterface $alias_manager, PathValidatorInterface $path_validator, WebformRequestInterface $request_handler, WebformElementManagerInterface $element_manager, WebformThirdPartySettingsManagerInterface $third_party_settings_manager, WebformMessageManagerInterface $message_manager, WebformTokenManagerInterface $token_manager, WebformStatesValidator $states_validator) {
     parent::__construct($entity_manager);
     $this->renderer = $renderer;
     $this->requestHandler = $request_handler;
@@ -169,6 +176,7 @@ class WebformSubmissionForm extends ContentEntityForm {
     $this->thirdPartySettingsManager = $third_party_settings_manager;
     $this->messageManager = $message_manager;
     $this->tokenManager = $token_manager;
+    $this->statesValidator = $states_validator;
   }
 
   /**
@@ -184,7 +192,8 @@ class WebformSubmissionForm extends ContentEntityForm {
       $container->get('plugin.manager.webform.element'),
       $container->get('webform.third_party_settings_manager'),
       $container->get('webform.message_manager'),
-      $container->get('webform.token_manager')
+      $container->get('webform.token_manager'),
+      $container->get('webform.states_validator')
     );
   }
 
@@ -220,33 +229,29 @@ class WebformSubmissionForm extends ContentEntityForm {
       $this->sourceEntity = $this->requestHandler->getCurrentSourceEntity(['webform', 'webform_submission']);
     }
 
-    // Load entity from token or saved draft when not editing or testing
-    // submission form.
-    if (!in_array($this->operation, ['edit', 'test'])) {
-      $token = $this->getRequest()->query->get('token');
-      if ($webform->getSetting('token_update') && $token) {
-        if ($webform_submissions_token = $this->storage->loadByProperties(['token' => $token])) {
-          $entity = reset($webform_submissions_token);
-        }
+    $token = $this->getRequest()->query->get('token');
+    if ($webform->getSetting('token_update') && $token) {
+      if ($webform_submissions_token = $this->storage->loadByProperties(['token' => $token])) {
+        $entity = reset($webform_submissions_token);
       }
-      elseif ($webform->getSetting('draft') != WebformInterface::DRAFT_NONE) {
-        if ($webform->getSetting('draft_multiple')) {
-          // Allow multiple drafts to be restored using token.
-          // This allows the webform's public facing URL to be used instead of
-          // the admin URL of the webform.
-          if ($token && ($webform_submissions_token = $this->storage->loadByProperties(['token' => $token, 'uid' => $this->currentUser()->id()]))) {
-            /** @var \Drupal\webform\WebformSubmissionInterface $draft_submission */
-            $draft_submission = reset($webform_submissions_token);
-            if ($draft_submission->isDraft()) {
-              $entity = $draft_submission;
-            }
+    }
+    elseif ($webform->getSetting('draft') != WebformInterface::DRAFT_NONE) {
+      if ($webform->getSetting('draft_multiple')) {
+        // Allow multiple drafts to be restored using token.
+        // This allows the webform's public facing URL to be used instead of
+        // the admin URL of the webform.
+        if ($token && ($webform_submissions_token = $this->storage->loadByProperties(['token' => $token, 'uid' => $this->currentUser()->id()]))) {
+          /** @var \Drupal\webform\WebformSubmissionInterface $draft_submission */
+          $draft_submission = reset($webform_submissions_token);
+          if ($draft_submission->isDraft()) {
+            $entity = $draft_submission;
           }
         }
-        else {
-          // Else load the most recent draft.
-          if ($webform_submission_draft = $this->storage->loadDraft($webform, $this->sourceEntity, $this->currentUser())) {
-            $entity = $webform_submission_draft;
-          }
+      }
+      else {
+        // Else load the most recent draft.
+        if ($webform_submission_draft = $this->storage->loadDraft($webform, $this->sourceEntity, $this->currentUser())) {
+          $entity = $webform_submission_draft;
         }
       }
     }
@@ -259,6 +264,20 @@ class WebformSubmissionForm extends ContentEntityForm {
    */
   protected function copyFormValuesToEntity(EntityInterface $entity, array $form, FormStateInterface $form_state) {
     parent::copyFormValuesToEntity($entity, $form, $form_state);
+
+    /* @var $webform_submission \Drupal\webform\WebformSubmissionInterface */
+    $webform_submission = $entity;
+    $webform = $webform_submission->getWebform();
+
+    // Get elements values from webform submission.
+    $values = array_intersect_key(
+      $form_state->getValues(),
+      $webform->getElementsInitializedFlattenedAndHasValue()
+    );
+
+    // Serialize the values as YAML and merge existing data.
+    $webform_submission->setData($values + $webform_submission->getData());
+
     // Set current page.
     if ($current_page = $this->getCurrentPage($form, $form_state)) {
       $entity->setCurrentPage($current_page);
@@ -1035,29 +1054,21 @@ class WebformSubmissionForm extends ContentEntityForm {
         call_user_func_array($form_state->prepareCallback($callback), [&$form, &$form_state]);
       }
     }
+
+    // Build webform submission with validated and processed data.
+    $this->entity = $this->buildEntity($form, $form_state);
+
+    // Server side #states API validation.
+    $this->statesValidator->validateForm($form, $form_state);
   }
 
   /**
    * {@inheritdoc}
    */
   public function submitForm(array &$form, FormStateInterface $form_state) {
-    /* @var $webform_submission \Drupal\webform\WebformSubmissionInterface */
-    $webform_submission = $this->entity;
-    $webform = $webform_submission->getWebform();
-
-    // Get elements values from webform submission.
-    $values = array_intersect_key(
-      $form_state->getValues(),
-      $webform->getElementsInitializedFlattenedAndHasValue()
-    );
-
-    // Serialize the values as YAML and merge existing data.
-    $webform_submission->setData($values + $webform_submission->getData());
-
     parent::submitForm($form, $form_state);
-
     // Submit webform via webform handler.
-    $this->getWebform()->invokeHandlers('submitForm', $form, $form_state, $webform_submission);
+    $this->getWebform()->invokeHandlers('submitForm', $form, $form_state, $this->entity);
   }
 
   /**
diff --git a/tests/modules/webform_test/config/install/webform.webform.test_form_states_server_required.yml b/tests/modules/webform_test/config/install/webform.webform.test_form_states_server_required.yml
new file mode 100644
index 00000000..204f0fa1
--- /dev/null
+++ b/tests/modules/webform_test/config/install/webform.webform.test_form_states_server_required.yml
@@ -0,0 +1,196 @@
+langcode: en
+status: open
+dependencies:
+  enforced:
+    module:
+      - webform_test
+open: null
+close: null
+uid: null
+template: false
+id: test_form_states_server_required
+title: 'Test: Form API #states server-side required/optional validation'
+description: 'Test Drupal''s #states API via server-side required/optional validation.'
+category: 'Test: Form API #states'
+elements: |
+  trigger:
+    '#type': details
+    '#title': triggers
+    '#open': true
+    trigger_checkbox:
+      '#type': checkbox
+      '#title': trigger_checkbox
+    trigger_textfield:
+      '#type': textfield
+      '#title': trigger_textfield
+    trigger_select:
+      '#type': select
+      '#title': trigger_select
+      '#options':
+        option: Option
+  dependent:
+    '#type': details
+    '#title': dependents
+    '#open': true
+    dependent_textfield_required:
+      '#type': textfield
+      '#title': dependent_textfield_required
+      '#description': '<b>Required:</b> checkbox:checked=true AND textfield:filled=true AND select:value=options'
+      '#states':
+        required:
+          ':input[name="trigger_checkbox"]':
+            checked: true
+          ':input[name="trigger_textfield"]':
+            filled: true
+          ':input[name="trigger_select"]':
+            value: option
+    dependent_select_other_required:
+      '#type': webform_select_other
+      '#title': dependent_select_other_required
+      '#options':
+        option_1: 'Option 1'
+        option_2: 'Option 2'
+        option_3: 'Option 3'
+      '#description': '<b>Required:</b> checkbox:checked=true OR textfield:filled=true OR select:value=options'
+      '#states':
+        required:
+          - ':input[name="trigger_checkbox"]':
+              checked: true
+          - or
+          - ':input[name="trigger_textfield"]':
+              filled: true
+          - or
+          - ':input[name="trigger_select"]':
+              value: option
+    dependent_textfield_optional:
+      '#type': textfield
+      '#title': dependent_textfield_optional
+      '#description': '<b>Optional:</b> checkbox:checked=true AND textfield:filled=true AND select:value=options'
+      '#states':
+        optional:
+          ':input[name="trigger_checkbox"]':
+            checked: true
+          ':input[name="trigger_textfield"]':
+            filled: true
+          ':input[name="trigger_select"]':
+            value: option
+    dependent_select_other_optional:
+      '#type': webform_select_other
+      '#title': dependent_select_other_optional
+      '#options':
+        option_1: 'Option 1'
+        option_2: 'Option 2'
+        option_3: 'Option 3'
+      '#description': '<b>Optional:</b> checkbox:checked=true OR textfield:filled=true OR select:value=options'
+      '#states':
+        optional:
+          - ':input[name="trigger_checkbox"]':
+              checked: true
+          - or
+          - ':input[name="trigger_textfield"]':
+              filled: true
+          - or
+          - ':input[name="trigger_select"]':
+              value: option
+css: ''
+javascript: ''
+settings:
+  ajax: false
+  page: true
+  page_submit_path: ''
+  page_confirm_path: ''
+  form_submit_once: false
+  form_exception_message: ''
+  form_open_message: ''
+  form_close_message: ''
+  form_previous_submissions: true
+  form_confidential: false
+  form_confidential_message: ''
+  form_convert_anonymous: false
+  form_prepopulate: false
+  form_prepopulate_source_entity: false
+  form_prepopulate_source_entity_required: false
+  form_prepopulate_source_entity_type: ''
+  form_reset: false
+  form_disable_autocomplete: false
+  form_novalidate: true
+  form_unsaved: false
+  form_disable_back: false
+  form_autofocus: false
+  form_details_toggle: false
+  submission_label: ''
+  submission_log: false
+  submission_user_columns: {  }
+  wizard_progress_bar: true
+  wizard_progress_pages: false
+  wizard_progress_percentage: false
+  wizard_start_label: ''
+  wizard_complete: true
+  wizard_complete_label: ''
+  preview: 0
+  preview_label: ''
+  preview_title: ''
+  preview_message: ''
+  preview_attributes: {  }
+  preview_excluded_elements: {  }
+  preview_exclude_empty: true
+  draft: none
+  draft_multiple: false
+  draft_auto_save: false
+  draft_saved_message: ''
+  draft_loaded_message: ''
+  confirmation_type: message
+  confirmation_title: ''
+  confirmation_message: ''
+  confirmation_url: ''
+  confirmation_attributes: {  }
+  confirmation_back: true
+  confirmation_back_label: ''
+  confirmation_back_attributes: {  }
+  limit_total: null
+  limit_total_message: ''
+  limit_user: null
+  limit_user_message: ''
+  purge: none
+  purge_days: null
+  entity_limit_total: null
+  entity_limit_user: null
+  results_disabled: false
+  results_disabled_ignore: false
+  token_update: false
+access:
+  create:
+    roles:
+      - anonymous
+      - authenticated
+    users: {  }
+    permissions: {  }
+  view_any:
+    roles: {  }
+    users: {  }
+    permissions: {  }
+  update_any:
+    roles: {  }
+    users: {  }
+    permissions: {  }
+  delete_any:
+    roles: {  }
+    users: {  }
+    permissions: {  }
+  purge_any:
+    roles: {  }
+    users: {  }
+    permissions: {  }
+  view_own:
+    roles: {  }
+    users: {  }
+    permissions: {  }
+  update_own:
+    roles: {  }
+    users: {  }
+    permissions: {  }
+  delete_own:
+    roles: {  }
+    users: {  }
+    permissions: {  }
+handlers: {  }
diff --git a/webform.routing.yml b/webform.routing.yml
index 921f23eb..583960b4 100644
--- a/webform.routing.yml
+++ b/webform.routing.yml
@@ -461,7 +461,7 @@ entity.webform_submission.log:
 entity.webform_submission.edit_form:
   path: '/admin/structure/webform/manage/{webform}/submission/{webform_submission}/edit'
   defaults:
-    _entity_form: 'webform_submission.edit'
+    _entity_form: 'webform_submission.default'
     _title_callback: 'Drupal\webform\Controller\WebformSubmissionController::title'
   requirements:
     _entity_access: 'webform_submission.update'
@@ -469,7 +469,7 @@ entity.webform_submission.edit_form:
 entity.webform_submission.edit_form.all:
   path: '/admin/structure/webform/manage/{webform}/submission/{webform_submission}/edit/all'
   defaults:
-    _entity_form: 'webform_submission.edit'
+    _entity_form: 'webform_submission.default'
     _title_callback: 'Drupal\webform\Controller\WebformSubmissionController::title'
     mode: disable_pages
   requirements:
diff --git a/webform.services.yml b/webform.services.yml
index e3fb59a5..fa969979 100644
--- a/webform.services.yml
+++ b/webform.services.yml
@@ -69,6 +69,10 @@ services:
     class: Drupal\webform\WebformTokenManager
     arguments: ['@module_handler', '@token']
 
+  webform.states_validator:
+    class: Drupal\webform\WebformStatesValidator
+    arguments: ['@plugin.manager.webform.element']
+
   # Breadcrumb builder.
 
   webform.breadcrumb:
