diff --git a/config/schema/webform.entity.webform.schema.yml b/config/schema/webform.entity.webform.schema.yml
index 20d3cc2bf..58c40309f 100644
--- a/config/schema/webform.entity.webform.schema.yml
+++ b/config/schema/webform.entity.webform.schema.yml
@@ -485,6 +485,9 @@
         token_update:
           type: boolean
           label: 'Allow updating a submission using token'
+        token_delete:
+          type: boolean
+          label: 'Allow deleting a submission using token'
         serial_disabled:
           type: boolean
           label: 'Next submission number disabled'
diff --git a/includes/webform.install.update.inc b/includes/webform.install.update.inc
index 3af205361..d1bf53ab0 100644
--- a/includes/webform.install.update.inc
+++ b/includes/webform.install.update.inc
@@ -3910,3 +3910,9 @@ function webform_update_8209() {
   }
 }
 
+/**
+ * Issue #3158114: Delete own submission with secure token not working.
+ */
+function webform_update_8210() {
+  _webform_update_webform_settings();
+}
diff --git a/includes/webform.theme.template.inc b/includes/webform.theme.template.inc
index f3c0e1717..67ed32864 100644
--- a/includes/webform.theme.template.inc
+++ b/includes/webform.theme.template.inc
@@ -326,14 +326,12 @@ function template_preprocess_webform_submission_information(array &$variables) {
     $variables['uri'] = Link::fromTextAndUrl($source_url->setAbsolute(FALSE)->toString(), $source_url);
   }
 
-  if ($webform->getSetting('token_view')) {
-    $token_view_url = $webform_submission->getTokenUrl('view');
-    $variables['token_view'] = Link::fromTextAndUrl($token_view_url->setAbsolute(FALSE)->toString(), $token_view_url);
-  }
-
-  if ($webform->getSetting('token_update')) {
-    $token_update_url = $webform_submission->getTokenUrl('update');
-    $variables['token_update'] = Link::fromTextAndUrl($token_update_url->setAbsolute(FALSE)->toString(), $token_update_url);
+  $token_operations = ['view', 'update', 'delete'];
+  foreach ($token_operations as $token_operation) {
+    if ($webform->getSetting('token_' . $token_operation)) {
+      $token_url = $webform_submission->getTokenUrl($token_operation);
+      $variables['token_' . $token_operation] = Link::fromTextAndUrl($token_url->setAbsolute(FALSE)->toString(), $token_url);
+    }
   }
 
   if (($source_entity = $webform_submission->getSourceEntity()) && $source_entity->hasLinkTemplate('canonical')) {
diff --git a/src/Entity/Webform.php b/src/Entity/Webform.php
index d1c392aa6..ab904ae15 100644
--- a/src/Entity/Webform.php
+++ b/src/Entity/Webform.php
@@ -1151,6 +1151,7 @@ class Webform extends ConfigEntityBundleBase implements WebformInterface {
       'results_customize' => FALSE,
       'token_view' => FALSE,
       'token_update' => FALSE,
+      'token_delete' => FALSE,
       'serial_disabled' => FALSE,
     ];
   }
diff --git a/src/Entity/WebformSubmission.php b/src/Entity/WebformSubmission.php
index 74b1395fe..158327979 100644
--- a/src/Entity/WebformSubmission.php
+++ b/src/Entity/WebformSubmission.php
@@ -571,6 +571,12 @@ class WebformSubmission extends ContentEntityBase implements WebformSubmissionIn
         $url = $this->getSourceUrl();
         break;
 
+      case 'delete':
+        /** @var \Drupal\webform\WebformRequestInterface $request_handler */
+        $request_handler = \Drupal::service('webform.request');
+        $url = $request_handler->getUrl($this, $this->getSourceEntity(), 'webform.user.submission.delete');
+        break;
+
       default:
         throw new \Exception("Token URL operation $operation is not supported");
     }
diff --git a/src/EntitySettings/WebformEntitySettingsSubmissionsForm.php b/src/EntitySettings/WebformEntitySettingsSubmissionsForm.php
index 6b041b0d2..292f4b2d1 100644
--- a/src/EntitySettings/WebformEntitySettingsSubmissionsForm.php
+++ b/src/EntitySettings/WebformEntitySettingsSubmissionsForm.php
@@ -224,6 +224,12 @@ class WebformEntitySettingsSubmissionsForm extends WebformEntitySettingsBaseForm
           $this->t("The 'tokenized' URL to update a submission will be available when viewing a submission's information and can be inserted into an email using the [webform_submission:update-url] token.") . ' ' .
           $this->t('Only webforms that are open to new submissions can be updated using the secure token.'),
       ],
+      'token_delete' => [
+        'title' => $this->t('Allow users to delete a submission using a secure token'),
+        'form_description' => $this->t("If checked users will be able to delete a submission using the webform's URL appended with the submission's (secure) token.") . ' ' .
+          $this->t("The 'tokenized' URL to update a submission will be available when viewing a submission's information and can be inserted into an email using the [webform_submission:delete-url] token.") . ' ' .
+          $this->t('Only webforms that are open to new submissions can be deleted using the secure token.'),
+      ],
       // Global behaviors.
       // @see \Drupal\webform\Form\WebformAdminSettingsForm
       'submission_log' => [
@@ -247,9 +253,11 @@ class WebformEntitySettingsSubmissionsForm extends WebformEntitySettingsBaseForm
           [':input[name="token_view"]' => ['checked' => TRUE]],
           'or',
           [':input[name="token_update"]' => ['checked' => TRUE]],
+          'or',
+          [':input[name="token_delete"]' => ['checked' => TRUE]],
         ],
       ],
-      '#weight' => $form['submission_behaviors']['token_update']['#weight'] + 1,
+      '#weight' => $form['submission_behaviors']['token_delete']['#weight'] + 1,
     ];
 
     // User settings.
diff --git a/src/Form/WebformSubmissionDeleteForm.php b/src/Form/WebformSubmissionDeleteForm.php
index 53b671536..2048a0302 100644
--- a/src/Form/WebformSubmissionDeleteForm.php
+++ b/src/Form/WebformSubmissionDeleteForm.php
@@ -5,6 +5,7 @@ namespace Drupal\webform\Form;
 use Drupal\Core\Entity\ContentEntityDeleteForm;
 use Drupal\Core\Entity\EntityRepositoryInterface;
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Url;
 use Drupal\webform\WebformRequestInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
@@ -174,8 +175,19 @@ class WebformSubmissionDeleteForm extends ContentEntityDeleteForm implements Web
    * {@inheritdoc}
    */
   public function getCancelUrl() {
-    $base_route_name = (strpos(\Drupal::routeMatch()->getRouteName(), 'webform.user.submission.delete') !== FALSE) ? 'webform.user.submissions' : 'webform.results_submissions';
-    return $this->requestHandler->getUrl($this->webform, $this->sourceEntity, $base_route_name);
+    if ($this->webform->access('submission_view_own') || $this->webform->access('submission_view_any')) {
+      $base_route_name = (strpos(\Drupal::routeMatch()->getRouteName(), 'webform.user.submission.delete') !== FALSE) ? 'webform.user.submissions' : 'webform.results_submissions';
+      return $this->requestHandler->getUrl($this->webform, $this->sourceEntity, $base_route_name);
+    }
+    elseif ($this->sourceEntity && $this->sourceEntity->hasLinkTemplate('canonical') && $this->sourceEntity->access('view')) {
+      return $this->sourceEntity->toUrl();
+    }
+    elseif ($this->webform->access('view')) {
+      return $this->webform->toUrl();
+    }
+    else {
+      return Url::fromRoute('<front>');
+    }
   }
 
   /**
diff --git a/src/WebformSubmissionAccessControlHandler.php b/src/WebformSubmissionAccessControlHandler.php
index 68c842818..8027159a9 100644
--- a/src/WebformSubmissionAccessControlHandler.php
+++ b/src/WebformSubmissionAccessControlHandler.php
@@ -81,15 +81,14 @@ class WebformSubmissionAccessControlHandler extends EntityAccessControlHandler i
       return WebformAccessResult::allowed($entity, TRUE);
     }
 
-    // Check view operation token access.
-    if ($operation === 'view'
-      && $entity->getWebform()->getSetting('token_view')) {
+    // Check view and delete operations token access.
+    if (($operation === 'view' || $operation === 'delete')
+      && $entity->getWebform()->getSetting('token_' . $operation)) {
       $token = $this->request->query->get('token');
       if ($token === $entity->getToken()) {
         return WebformAccessResult::allowed($entity)
           ->addCacheContexts(['url.query_args:token']);
       }
-
     }
 
     // Check 'any' or 'own' webform submission permissions.
diff --git a/tests/modules/webform_test/config/install/webform.webform.test_token_view_update.yml b/tests/modules/webform_test/config/install/webform.webform.test_token_operations.yml
similarity index 93%
rename from tests/modules/webform_test/config/install/webform.webform.test_token_view_update.yml
rename to tests/modules/webform_test/config/install/webform.webform.test_token_operations.yml
index 0dc7bb753..018f85551 100644
--- a/tests/modules/webform_test/config/install/webform.webform.test_token_view_update.yml
+++ b/tests/modules/webform_test/config/install/webform.webform.test_token_operations.yml
@@ -11,9 +11,9 @@ weight: 0
 uid: null
 template: false
 archive: false
-id: test_token_view_update
-title: 'Test: Token: View & Update'
-description: 'Test viewing and updating submission using secure token.'
+id: test_token_operations
+title: 'Test: Token: Operations (View, Update, & Delete)'
+description: 'Test viewing, updating, and deleting a submission using secure token.'
 category: 'Test: Token'
 elements: |
   textfield:
@@ -124,6 +124,7 @@ settings:
   confirmation_message: |
     <p>You can view your submission via <a href="[webform_submission:view-url]">[webform_submission:view-url:relative]</a></p>
     <p>You can update your submission via <a href="[webform_submission:update-url]">[webform_submission:update-url:relative]</a></p>
+    <p>You can delete your submission via <a href="[webform_submission:delete-url]">[webform_submission:delete-url:relative]</a></p>
 
   confirmation_url: ''
   confirmation_attributes: {  }
@@ -152,6 +153,7 @@ settings:
   results_customize: false
   token_view: true
   token_update: true
+  token_delete: true
   serial_disabled: false
 access:
   create:
@@ -224,8 +226,8 @@ handlers:
       subject: _default
       body: |
         <a href="[webform_submission:view-url]">[webform_submission:view-url]</a><br/>
-        <a href="[webform_submission:update-url]">[webform_submission:update-url]</a>
-
+        <a href="[webform_submission:update-url]">[webform_submission:update-url]</a><br/>
+        <a href="[webform_submission:delete-url]">[webform_submission:delete-url]</a>
       excluded_elements: {  }
       ignore_access: false
       exclude_empty: true
diff --git a/tests/src/Functional/WebformSubmissionTokenUpdateTest.php b/tests/src/Functional/WebformSubmissionTokenOperationsTest.php
similarity index 87%
rename from tests/src/Functional/WebformSubmissionTokenUpdateTest.php
rename to tests/src/Functional/WebformSubmissionTokenOperationsTest.php
index d13c38846..4bea2078c 100644
--- a/tests/src/Functional/WebformSubmissionTokenUpdateTest.php
+++ b/tests/src/Functional/WebformSubmissionTokenOperationsTest.php
@@ -6,11 +6,11 @@ use Drupal\webform\Entity\Webform;
 use Drupal\webform\Entity\WebformSubmission;
 
 /**
- * Tests for updating webform submission using tokenized URL.
+ * Tests for operations on a webform submission using a tokenized URL.
  *
  * @group webform
  */
-class WebformSubmissionTokenUpdateTest extends WebformBrowserTestBase {
+class WebformSubmissionTokenOperationsTest extends WebformBrowserTestBase {
 
   /**
    * Modules to enable.
@@ -24,15 +24,15 @@ class WebformSubmissionTokenUpdateTest extends WebformBrowserTestBase {
    *
    * @var array
    */
-  protected static $testWebforms = ['test_token_view_update'];
+  protected static $testWebforms = ['test_token_operations'];
 
   /**
-   * Test updating webform submission using tokenized URL.
+   * Test operations on a webform submission using a tokenized URL.
    */
-  public function testTokenUpdateTest() {
+  public function testTokenOperationsTest() {
     $normal_user = $this->drupalCreateUser();
 
-    $webform = Webform::load('test_token_view_update');
+    $webform = Webform::load('test_token_operations');
 
     /**************************************************************************/
 
@@ -40,6 +40,7 @@ class WebformSubmissionTokenUpdateTest extends WebformBrowserTestBase {
     $this->drupalLogin($this->rootUser);
     $sid = $this->postSubmissionTest($webform);
     $webform_submission = WebformSubmission::load($sid);
+
     // Check confirmation page's URL token.
     $token_url = $webform_submission->getTokenUrl();
     $link_label = $token_url->setAbsolute(FALSE)->toString();
@@ -93,7 +94,7 @@ class WebformSubmissionTokenUpdateTest extends WebformBrowserTestBase {
       ->save();
 
     // Check that access is denied for anonymous user.
-    $this->drupalGet('/webform/test_token_view_update');
+    $this->drupalGet('/webform/test_token_operations');
     $this->assertResponse(403);
 
     // Check token view access allowed for anonymous user.
diff --git a/webform.tokens.inc b/webform.tokens.inc
index 404adbef9..39132996a 100644
--- a/webform.tokens.inc
+++ b/webform.tokens.inc
@@ -82,6 +82,11 @@ function webform_token_info() {
     'description' => t('The URL that can used to update the webform submission. The webform must be configured to allow users to update a submission using a secure token.'),
     'type' => 'url',
   ];
+  $webform_submission['delete-url'] = [
+    'name' => t('Delete (token) URL'),
+    'description' => t('The URL that can used to delete the webform submission. The webform must be configured to allow users to delete a submission using a secure token.'),
+    'type' => 'url',
+  ];
   $webform_submission['langcode'] = [
     'name' => t('Langcode'),
     'description' => t('The language code of the webform submission.'),
@@ -538,11 +543,9 @@ function webform_tokens($type, $tokens, array $data, array $options, BubbleableM
           break;
 
         case 'view-url':
-          $replacements[$original] = $webform_submission->getTokenUrl('view')->toString();
-          break;
-
         case 'update-url':
-          $replacements[$original] = $webform_submission->getTokenUrl('update')->toString();
+        case 'delete-url':
+          $replacements[$original] = $webform_submission->getTokenUrl(str_replace('-url', '', $name))->toString();
           break;
 
         case 'token':
@@ -735,16 +738,14 @@ function webform_tokens($type, $tokens, array $data, array $options, BubbleableM
     if (($submitted_to_tokens = $token_service->findWithPrefix($tokens, 'submitted-to')) && ($submitted_to = $webform_submission->getSourceEntity(TRUE) ?: $webform_submission->getWebform())) {
       $replacements += $token_service->generate($submitted_to->getEntityTypeId(), $submitted_to_tokens, [$submitted_to->getEntityTypeId() => $submitted_to], $options, $bubbleable_metadata);
     }
-    foreach (['view-url', 'update-url', 'source-url'] as $token) {
+    foreach (['view-url', 'update-url', 'delete-url', 'source-url'] as $token) {
       if ($url_tokens = $token_service->findWithPrefix($tokens, $token)) {
         $url = NULL;
         switch ($token) {
           case 'view-url':
-            $url = $webform_submission->getTokenUrl('view');
-            break;
-
           case 'update-url':
-            $url = $webform_submission->getTokenUrl('update');
+          case 'delete-url':
+            $url = $webform_submission->getTokenUrl(str_replace('-url', '', $token));
             break;
 
           case 'source-url':
