diff --git a/djblets/db/fields/json_field.py b/djblets/db/fields/json_field.py
index f050746d4228160ec3a24583c7d399f51ac08f6e..e6b1923f3045a36b73b2eba821428fe027bd7858 100644
--- a/djblets/db/fields/json_field.py
+++ b/djblets/db/fields/json_field.py
@@ -29,6 +29,11 @@ logger = logging.getLogger(__name__)
 #: This is currently very generic, but may be expanded or aliased in the
 #: future.
 #:
+#: Deprecated:
+#:     3.3
+#:     Consumers should use the more complete
+#:     :py:class:`djblets.util.typing.JSONValue` instead.
+#:
 #: Version Added:
 #:     3.1
 JSONValue: TypeAlias = object
@@ -36,6 +41,11 @@ JSONValue: TypeAlias = object
 
 #: A type for a JSON dictionary.
 #:
+#: Deprecated:
+#:     3.3
+#:     Consumers should use the more complete
+#:     :py:class:`djblets.util.typing.JSONDict` instead.
+#:
 #: Version Added:
 #:     3.1
 JSONDict: TypeAlias = Dict[str, JSONValue]
diff --git a/djblets/features/feature.py b/djblets/features/feature.py
index 5d54cc0e5121f3ac5846a3520af4a78ae861ce51..4a0c9fadd74b56e03ebc66369ca9c9fa3282f921 100644
--- a/djblets/features/feature.py
+++ b/djblets/features/feature.py
@@ -8,9 +8,7 @@ from djblets.features.checkers import get_feature_checker
 from djblets.features.level import FeatureLevel
 
 if TYPE_CHECKING:
-    from django.utils.functional import _StrOrPromise
-else:
-    _StrOrPromise = str
+    from djblets.util.typing import StrOrPromise
 
 
 class Feature:
@@ -34,10 +32,10 @@ class Feature:
     feature_id: Optional[str] = None
 
     #: The name of the feature.
-    name: Optional[_StrOrPromise] = None
+    name: Optional[StrOrPromise] = None
 
     #: A summary of the feature.
-    summary: Optional[_StrOrPromise] = None
+    summary: Optional[StrOrPromise] = None
 
     #: Stability level of the feature.
     level: FeatureLevel = FeatureLevel.EXPERIMENTAL
diff --git a/djblets/integrations/integration.py b/djblets/integrations/integration.py
index c232b2e6915ea19b3a3940ad30063cd693e17f9b..6c938088ae24ddcec6c7b5f9f54a8393ab10deeb 100644
--- a/djblets/integrations/integration.py
+++ b/djblets/integrations/integration.py
@@ -9,10 +9,10 @@ from typing_extensions import TypeAlias
 from djblets.integrations.forms import IntegrationConfigForm
 
 if TYPE_CHECKING:
-    from django.utils.functional import _StrOrPromise
     from djblets.extensions.hooks import ExtensionHook
     from djblets.integrations.manager import IntegrationManager
     from djblets.integrations.models import BaseIntegrationConfig
+    from djblets.util.typing import StrOrPromise
 
 
 class Integration(object):
@@ -50,10 +50,10 @@ class Integration(object):
     integration_id: Optional[str] = None
 
     #: The display name of the integration.
-    name: Optional[_StrOrPromise] = None
+    name: Optional[StrOrPromise] = None
 
     #: A short description of this integration, in plain text format.
-    description: Optional[_StrOrPromise] = None
+    description: Optional[StrOrPromise] = None
 
     #: Static paths for the integration's icon.
     #:
diff --git a/djblets/registries/registry.py b/djblets/registries/registry.py
index 9ff380011ef1403639fd3f51b4d664da3e0a0468..a31fecd51adc43f5cf90ef4de03347ad8d5e3853 100644
--- a/djblets/registries/registry.py
+++ b/djblets/registries/registry.py
@@ -18,11 +18,7 @@ from djblets.registries.errors import (AlreadyRegisteredError,
                                        ItemLookupError,
                                        RegistrationError)
 from djblets.registries.signals import registry_populating
-
-if TYPE_CHECKING:
-    from django.utils.functional import _StrOrPromise
-else:
-    _StrOrPromise = str
+from djblets.util.typing import StrOrPromise
 
 
 #: A mapping of error types to error messages.
@@ -31,7 +27,7 @@ else:
 #:
 #: Version Added:
 #:     3.3
-RegistryErrorsDict: TypeAlias = Dict[str, _StrOrPromise]
+RegistryErrorsDict: TypeAlias = Dict[str, StrOrPromise]
 
 
 #: A generic type for items stored in a registry.
diff --git a/djblets/siteconfig/models.py b/djblets/siteconfig/models.py
index 3d7eeeafb786a1a91d9c5b1926726e3487c5894f..694e1f36b0119e31ad95cf598e1d6098b2197b92 100644
--- a/djblets/siteconfig/models.py
+++ b/djblets/siteconfig/models.py
@@ -9,8 +9,9 @@ from django.db import models
 from typing_extensions import TypeAlias
 
 from djblets.cache.synchronizer import GenerationSynchronizer
-from djblets.db.fields.json_field import JSONDict, JSONField, JSONValue
+from djblets.db.fields.json_field import JSONField
 from djblets.siteconfig.managers import SiteConfigurationManager
+from djblets.util.typing import JSONDict, JSONValue
 
 
 #: An alias for valid value types in site configuration settings.
diff --git a/djblets/util/symbols.py b/djblets/util/symbols.py
new file mode 100644
index 0000000000000000000000000000000000000000..7fec6feab8481354564b50c0e8060c2c3a747472
--- /dev/null
+++ b/djblets/util/symbols.py
@@ -0,0 +1,23 @@
+"""Common symbols useful for function signatures.
+
+Version Added:
+    3.3
+"""
+
+
+class UnsetSymbol:
+    """A symbol indicating an unset value.
+
+    This can be useful in functions that take default values to distinguish
+    between a value not provided and a false/``None`` value.
+
+    Version Added:
+        3.3
+    """
+
+
+#: An instance of a symbol indicating an unset value.
+#:
+#: Version Added:
+#:     3.3
+UNSET = UnsetSymbol()
diff --git a/djblets/util/typing.py b/djblets/util/typing.py
new file mode 100644
index 0000000000000000000000000000000000000000..e7aed23dcf8e18d884f9acef64436e9e84fb45d9
--- /dev/null
+++ b/djblets/util/typing.py
@@ -0,0 +1,72 @@
+"""Common type definitions used for Djblets and consuming projects.
+
+Version Added:
+    3.3
+"""
+
+from __future__ import annotations
+
+from typing import Any, Dict, List, NewType, TYPE_CHECKING, Union
+
+from typing_extensions import TypeAlias
+
+if TYPE_CHECKING:
+    from django.utils.functional import _StrOrPromise, _StrPromise
+else:
+    from django.utils.functional import Promise
+
+    # The main reason we're using NewType here is to avoid Sphinx thinking
+    # this is an attribute during doc generation. At runtime here, NewType()
+    # will just return Promise.
+    _StrPromise: TypeAlias = NewType('StrPromise', Promise)
+    _StrOrPromise: TypeAlias = Union[str, _StrPromise]
+
+
+#: A type indicating a valid value in JSON data.
+#:
+#: Version Added:
+#:     3.3
+JSONValue: TypeAlias = Union[
+    'JSONDict',
+    'JSONList',
+    None,
+    bool,
+    float,
+    int,
+    str,
+]
+
+
+#: A type for a JSON dictionary mapping strings to JSON vlaues.
+#:
+#: Version Added:
+#:     3.3
+JSONDict: TypeAlias = Dict[str, JSONValue]
+
+
+#: A type for a JSON list of values.
+#:
+#: Version Added:
+#:     3.3
+JSONList: TypeAlias = List[JSONValue]
+
+
+#: A type indicating a dictionary used for keyword arguments.
+#:
+#: Version Added:
+#:     3.3
+KwargsDict: TypeAlias = Dict[str, Any]
+
+
+#: A type indicating a Unicode string or lazily-localized string.
+#:
+#: Version Added:
+#:     3.3
+StrOrPromise: TypeAlias = _StrOrPromise
+
+
+#: A type indicating a lazily-localized string.
+#:
+#: Version Added:
+#:     3.3
+StrPromise: TypeAlias = _StrPromise
diff --git a/docs/djblets/coderef/index.rst b/docs/djblets/coderef/index.rst
index 73aa4d9df429fb363e638788dfc88bccf61fba8d..6313ca2dd738bda5318c0b3d648a1388ede63324 100644
--- a/docs/djblets/coderef/index.rst
+++ b/docs/djblets/coderef/index.rst
@@ -490,12 +490,14 @@ Generic Utilities
    djblets.util.json_utils
    djblets.util.properties
    djblets.util.serializers
+   djblets.util.symbols
    djblets.util.templatetags.djblets_deco
    djblets.util.templatetags.djblets_email
    djblets.util.templatetags.djblets_forms
    djblets.util.templatetags.djblets_images
    djblets.util.templatetags.djblets_js
    djblets.util.templatetags.djblets_utils
+   djblets.util.typing
    djblets.util.views
 
 
