diff --git a/xarray/core/dataset.py b/xarray/core/dataset.py
index a7dedd2ed07..36d0614d11f 100644
--- a/xarray/core/dataset.py
+++ b/xarray/core/dataset.py
@@ -7009,17 +7009,17 @@ def reduce(
                 if not reduce_dims:
                     variables[name] = var
             else:
-                if (
-                    # Some reduction functions (e.g. std, var) need to run on variables
-                    # that don't have the reduce dims: PR5393
-                    not is_extension_array_dtype(var.dtype)
-                    and (
-                        not reduce_dims
-                        or not numeric_only
-                        or np.issubdtype(var.dtype, np.number)
-                        or (var.dtype == np.bool_)
-                    )
-                ):
+
+                is_numeric = (not is_extension_array_dtype(var.dtype)) and (
+                    np.issubdtype(var.dtype, np.number) or var.dtype == np.bool_
+                )
+
+                # pass through non-numeric scalar
+                if numeric_only and not is_numeric and var.ndim == 0:
+                    variables[name] = var
+
+                elif not reduce_dims or not numeric_only or is_numeric:
+
                     # prefer to aggregate over axis=None rather than
                     # axis=(0, 1) if they will be equivalent, because
                     # the former is often more efficient
diff --git a/xarray/tests/test_dataset.py b/xarray/tests/test_dataset.py
index 1178498de19..65d2575ef68 100644
--- a/xarray/tests/test_dataset.py
+++ b/xarray/tests/test_dataset.py
@@ -5661,14 +5661,35 @@ def test_reduce_non_numeric(self) -> None:
             data = np.random.randint(0, 100, size=size).astype(np.str_)
             data1[v] = (dims, data, {"foo": "variable"})
         # var4 is extension array categorical and should be dropped
-        assert (
-            "var4" not in data1.mean()
-            and "var5" not in data1.mean()
-            and "var6" not in data1.mean()
-        )
+
+        assert "var4" not in data1.mean()
+        assert "var5" not in data1.mean()
+        assert "var6" not in data1.mean()
+
         assert_equal(data1.mean(), data2.mean())
         assert_equal(data1.mean(dim="dim1"), data2.mean(dim="dim1"))
-        assert "var5" not in data1.mean(dim="dim2") and "var6" in data1.mean(dim="dim2")
+
+        assert "var5" not in data1.mean(dim="dim2")
+        assert "var6" in data1.mean(dim="dim2")
+
+    @pytest.mark.parametrize("op", ("sum", "prod", "mean", "std"))
+    def test_reduce_non_numeric_scalar(self, op) -> None:
+        # enusure non-numeric scalar is passed through
+
+        data_orig = create_test_data(seed=44, dim_sizes=(1, 2, 3))
+
+        # add a scalar
+        data = data_orig.assign(var4="string")
+
+        result = getattr(data, op)()
+        expected = getattr(data_orig, op)().assign(var4="string")
+
+        assert_equal(result, expected)
+
+        result = getattr(data, op)("dim1")
+        expected = getattr(data_orig, op)("dim1").assign(var4="string")
+
+        assert_equal(result, expected)
 
     @pytest.mark.filterwarnings(
         "ignore:Once the behaviour of DataArray:DeprecationWarning"