diff --git a/core/includes/errors.inc b/core/includes/errors.inc
index 23ed7d4bb7880033e731c07eada81bec011e1482..62179edf63ce3ecbbbdb851a5acbec70bc246a63 100644
--- a/core/includes/errors.inc
+++ b/core/includes/errors.inc
@@ -79,6 +79,7 @@ function _drupal_error_handler_real($error_level, $message, $filename, $line) {
       'severity_level' => $severity_level,
       'backtrace' => $backtrace,
       '@backtrace_string' => (new \Exception())->getTraceAsString(),
+      'exception' => NULL,
     ], $recoverable || $to_string);
   }
   // If the site is a test site then fail for user deprecations so they can be
@@ -133,10 +134,12 @@ function error_displayable($error = NULL) {
  * Logs a PHP error or exception and displays an error page in fatal cases.
  *
  * @param $error
- *   An array with the following keys: %type, @message, %function, %file,
- *   %line, @backtrace_string, severity_level, and backtrace. All the parameters
- *   are plain-text, with the exception of @message, which needs to be an HTML
- *   string, and backtrace, which is a standard PHP backtrace.
+ *   An array with the following keys: %type, @message, %function, %file, %line,
+ *   @backtrace_string, severity_level, backtrace, and exception. All the
+ *   parameters are plain-text, with the exception of @message, which needs to
+ *   be an HTML string, backtrace, which is a standard PHP backtrace, and
+ *   exception, which is the exception object (or NULL if the error is not an
+ *   exception).
  * @param bool $fatal
  *   TRUE for:
  *   - An exception is thrown and not caught by something else.
@@ -146,13 +149,12 @@ function error_displayable($error = NULL) {
 function _drupal_log_error($error, $fatal = FALSE) {
   $is_installer = InstallerKernel::installationAttempted();
 
-  // Remove 'severity_level' as is not a valid replacement for t().
-  $severity = $error['severity_level'];
-  unset($error['severity_level']);
-
-  // Backtrace array is not a valid replacement value for t().
+  // Backtrace, exception and 'severity_level' are not valid replacement values
+  // for t().
   $backtrace = $error['backtrace'];
-  unset($error['backtrace']);
+  $exception = $error['exception'];
+  $severity = $error['severity_level'];
+  unset($error['backtrace'], $error['exception'], $error['severity_level']);
 
   // When running inside the testing framework, we relay the errors
   // to the tested site by the way of HTTP headers.
@@ -167,10 +169,10 @@ function _drupal_log_error($error, $fatal = FALSE) {
   // installer.
   if (\Drupal::hasService('logger.factory')) {
     try {
-      // Provide the PHP backtrace to logger implementations. Add
+      // Provide the PHP backtrace and exception to logger implementations. Add
       // 'severity_level' to the context to maintain BC and allow logging
       // implementations to use it.
-      \Drupal::logger('php')->log($severity, '%type: @message in %function (line %line of %file) @backtrace_string.', $error + ['backtrace' => $backtrace, 'severity_level' => $severity]);
+      \Drupal::logger('php')->log($severity, '%type: @message in %function (line %line of %file) @backtrace_string.', $error + ['backtrace' => $backtrace, 'exception' => $exception, 'severity_level' => $severity]);
     }
     catch (\Exception $e) {
       // We can't log, for example because the database connection is not
diff --git a/core/includes/update.inc b/core/includes/update.inc
index bea0c861e37a979a4f231f115de20f22001e28c8..d5818d005aaab967209d363737ba7687d483d6ec 100644
--- a/core/includes/update.inc
+++ b/core/includes/update.inc
@@ -231,8 +231,7 @@ function update_do_one($module, $number, $dependency_map, &$context) {
       watchdog_exception('update', $e);
 
       $variables = Error::decodeException($e);
-      unset($variables['backtrace']);
-      unset($variables['severity_level']);
+      unset($variables['backtrace'], $variables['exception'], $variables['severity_level']);
       $ret['#abort'] = ['success' => FALSE, 'query' => t('%type: @message in %function (line %line of %file).', $variables)];
     }
   }
@@ -299,7 +298,7 @@ function update_invoke_post_update($function, &$context) {
       watchdog_exception('update', $e);
 
       $variables = Error::decodeException($e);
-      unset($variables['backtrace']);
+      unset($variables['backtrace'], $variables['exception']);
       $ret['#abort'] = [
         'success' => FALSE,
         'query' => t('%type: @message in %function (line %line of %file).', $variables),
diff --git a/core/lib/Drupal/Core/EventSubscriber/FinalExceptionSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/FinalExceptionSubscriber.php
index a2a09ecf54c922ee83ec752e4b1a23ea20f1f6de..87d716932296c08bad8c0e6958d0df5ee804bece 100644
--- a/core/lib/Drupal/Core/EventSubscriber/FinalExceptionSubscriber.php
+++ b/core/lib/Drupal/Core/EventSubscriber/FinalExceptionSubscriber.php
@@ -93,8 +93,7 @@ public function onException(ExceptionEvent $event) {
 
       $error = $this->simplifyFileInError($error);
 
-      unset($error['backtrace']);
-      unset($error['severity_level']);
+      unset($error['backtrace'], $error['exception'], $error['severity_level']);
 
       if (!$this->isErrorLevelVerbose()) {
         // Without verbose logging, use a simple message.
diff --git a/core/lib/Drupal/Core/Utility/Error.php b/core/lib/Drupal/Core/Utility/Error.php
index 092f7626e21031f73a0b4b34e6977a293bf86781..306486ed7a56e056b1491a49b27a6d51b9d73b82 100644
--- a/core/lib/Drupal/Core/Utility/Error.php
+++ b/core/lib/Drupal/Core/Utility/Error.php
@@ -71,6 +71,7 @@ public static function decodeException($exception) {
       'severity_level' => static::ERROR,
       'backtrace' => $backtrace,
       '@backtrace_string' => $exception->getTraceAsString(),
+      'exception' => $exception,
     ];
   }
 
@@ -86,7 +87,7 @@ public static function decodeException($exception) {
   public static function renderExceptionSafe($exception) {
     $decode = static::decodeException($exception);
     $backtrace = $decode['backtrace'];
-    unset($decode['backtrace']);
+    unset($decode['backtrace'], $decode['exception']);
     // Remove 'main()'.
     array_shift($backtrace);
 
diff --git a/core/modules/dblog/src/Logger/DbLog.php b/core/modules/dblog/src/Logger/DbLog.php
index 5933e222810c35c183d20cbf45ba1b93a9d3776a..4207a5c9db09fb62634a4d188628f37bd242b57b 100644
--- a/core/modules/dblog/src/Logger/DbLog.php
+++ b/core/modules/dblog/src/Logger/DbLog.php
@@ -53,8 +53,8 @@ public function __construct(Connection $connection, LogMessageParserInterface $p
    * {@inheritdoc}
    */
   public function log($level, $message, array $context = []) {
-    // Remove any backtraces since they may contain an unserializable variable.
-    unset($context['backtrace']);
+    // Remove backtrace and exception since they may contain an unserializable variable.
+    unset($context['backtrace'], $context['exception']);
 
     // Convert PSR3-style messages to \Drupal\Component\Render\FormattableMarkup
     // style, so they can be translated too in runtime.
diff --git a/core/tests/Drupal/Tests/Core/Error/DrupalLogErrorTest.php b/core/tests/Drupal/Tests/Core/Error/DrupalLogErrorTest.php
index a867cd196b0a4be154811240e0392c70a1b7c6a9..40103f08abba33e0f370d457bfef02e95ac89309 100644
--- a/core/tests/Drupal/Tests/Core/Error/DrupalLogErrorTest.php
+++ b/core/tests/Drupal/Tests/Core/Error/DrupalLogErrorTest.php
@@ -35,6 +35,7 @@ public function testFatalExitCode() {
   '@backtrace_string' => 'backtrace',
   'severity_level' => 0,
   'backtrace' => [],
+  'exception' => NULL,
 ];
 _drupal_log_error($error, TRUE);
 EOT;