diff --git a/housekeeping/base.py b/housekeeping/base.py
index d84314c0819423deb60f4eb6ff03b8bc6fa18534..b2e9b4342a02177fbe037136210db16270868bc0 100644
--- a/housekeeping/base.py
+++ b/housekeeping/base.py
@@ -3,7 +3,7 @@
 from __future__ import annotations
 
 import warnings
-from typing import Type, TYPE_CHECKING
+from typing import Callable, Type, TYPE_CHECKING, Union
 
 from typing_extensions import TypeAlias
 
@@ -97,3 +97,13 @@ class BasePendingRemovalWarning(BaseDeprecationWarningMixin,
 
 #: An alias for representing a BaseDeprecationWarningMixin subclass.
 DeprecationWarningType: TypeAlias = Type[BaseDeprecationWarningMixin]
+
+
+#: An alias for a DeprecationWarningType or a callable returning one.
+#:
+#: Version Added:
+#:     1.1
+DeprecationWarningTypeOrCallable: TypeAlias = Union[
+    DeprecationWarningType,
+    Callable[[], DeprecationWarningType],
+]
diff --git a/housekeeping/classes.py b/housekeeping/classes.py
index fba90577134112fe18e2a547caf0b50d3a198d62..4167fb936e748571e92c23477662f2e7efcee4c1 100644
--- a/housekeeping/classes.py
+++ b/housekeeping/classes.py
@@ -4,7 +4,7 @@ from __future__ import annotations
 
 from typing import Optional, Type
 
-from housekeeping.base import DeprecationWarningType
+from housekeeping.base import DeprecationWarningTypeOrCallable
 from housekeeping.helpers import emit_warning, format_display_name
 
 
@@ -88,14 +88,15 @@ class ClassDeprecatedMixin:
     _housekeeping_base_cls: Optional[Type] = None
     _housekeeping_subclass_deprecation_msg: Optional[str] = None
     _housekeeping_init_deprecation_msg: Optional[str] = None
-    _housekeeping_warning_cls: Optional[DeprecationWarningType] = None
+    _housekeeping_warning_cls: Optional[DeprecationWarningTypeOrCallable] = \
+        None
 
     def __init_subclass__(
         cls,
         *,
         init_deprecation_msg: Optional[str] = None,
         subclass_deprecation_msg: Optional[str] = None,
-        warning_cls: Optional[DeprecationWarningType] = None,
+        warning_cls: Optional[DeprecationWarningTypeOrCallable] = None,
         **kwargs,
     ) -> None:
         """Initialize a subclass.
@@ -112,12 +113,19 @@ class ClassDeprecatedMixin:
                 A custom deprecation message to use when subclassing the
                 class directly.
 
-            warning_cls (type, optional):
-                The type of warning class to use.
+            warning_cls (type or callable, optional):
+                The type of warning class to use, or a callable returning one.
 
                 This must be provided for the class using this mixin. It
                 will be ignored for subclasses.
 
+                A callable can be used to avoid circular references.
+
+                Version Changed:
+                    1.1:
+                    This can now be either a warning class or a function
+                    that returns one.
+
             **kwargs (dict):
                 Additional keyword arguments to pass to the parent.
         """
@@ -146,7 +154,8 @@ class ClassDeprecatedMixin:
 
             message = cls._housekeeping_subclass_deprecation_msg
 
-            if cls._housekeeping_base_cls in cls.__bases__:
+            if (cls._housekeeping_base_cls in cls.__bases__ and
+                not getattr(cls, 'housekeeping_skip_warning', False)):
                 emit_warning(
                     warning_cls,
                     deprecation_msg=message or (
@@ -275,7 +284,8 @@ class ClassMovedMixin:
     _housekeeping_init_deprecation_msg: Optional[str] = None
     _housekeeping_new_base_cls: Optional[Type] = None
     _housekeeping_subclass_deprecation_msg: Optional[str] = None
-    _housekeeping_warning_cls: Optional[DeprecationWarningType] = None
+    _housekeeping_warning_cls: Optional[DeprecationWarningTypeOrCallable] = \
+        None
 
     def __init_subclass__(
         cls,
@@ -283,7 +293,7 @@ class ClassMovedMixin:
         init_deprecation_msg: Optional[str] = None,
         subclass_deprecation_msg: Optional[str] = None,
         new_base_cls: Optional[Type] = None,
-        warning_cls: Optional[DeprecationWarningType] = None,
+        warning_cls: Optional[DeprecationWarningTypeOrCallable] = None,
         **kwargs,
     ) -> None:
         """Initialize a subclass.
@@ -300,12 +310,19 @@ class ClassMovedMixin:
                 A custom deprecation message to use when subclassing the
                 class directly.
 
-            warning_cls (type, optional):
-                The type of warning class to use.
+            warning_cls (type or callable, optional):
+                The type of warning class to use, or a callable returning one.
 
                 This must be provided for the class using this mixin. It
                 will be ignored for subclasses.
 
+                A callable can be used to avoid circular references.
+
+                Version Changed:
+                    1.1:
+                    This can now be either a warning class or a function
+                    that returns one.
+
             **kwargs (dict):
                 Additional keyword arguments to pass to the parent.
         """
@@ -337,7 +354,8 @@ class ClassMovedMixin:
 
             message = cls._housekeeping_subclass_deprecation_msg
 
-            if cls._housekeeping_base_cls in cls.__bases__:
+            if (cls._housekeeping_base_cls in cls.__bases__ and
+                not getattr(cls, 'housekeeping_skip_warning', False)):
                 emit_warning(
                     warning_cls,
                     deprecation_msg=message or (
diff --git a/housekeeping/functions.py b/housekeeping/functions.py
index 6e8014a134a118c1d424ab3e3f2ec08b2c54e044..afdfcd71f1c91d3a81cef48ac9341af4c6c8bdd5 100644
--- a/housekeeping/functions.py
+++ b/housekeeping/functions.py
@@ -7,7 +7,8 @@ from functools import wraps
 from typing import (Any, Callable, Dict, List, Optional, Tuple, TypeVar,
                     Union, cast)
 
-from housekeeping.base import DEFAULT_STACK_LEVEL, DeprecationWarningType
+from housekeeping.base import (DEFAULT_STACK_LEVEL,
+                               DeprecationWarningTypeOrCallable)
 from housekeeping.helpers import LazyObject, emit_warning, format_display_name
 
 
@@ -16,7 +17,7 @@ _ValueT = TypeVar('_ValueT')
 
 
 def deprecated_arg_value(
-    warning_cls: DeprecationWarningType,
+    warning_cls: DeprecationWarningTypeOrCallable,
     *,
     owner_name: str,
     value: _ValueT,
@@ -46,8 +47,15 @@ def deprecated_arg_value(
     Custom messages can also be provided.
 
     Args:
-        warning_cls (type, optional):
-            The class to use for the warning.
+        warning_cls (type or callable):
+            The type of warning class to use, or a callable returning one.
+
+            A callable can be used to avoid circular references.
+
+            Version Changed:
+                1.1:
+                This can now be either a warning class or a function
+                that returns one.
 
         owner_name (str):
             The name of the owner of this argument.
@@ -136,7 +144,7 @@ def deprecated_arg_value(
 
 
 def deprecate_non_keyword_only_args(
-    warning_cls: DeprecationWarningType,
+    warning_cls: DeprecationWarningTypeOrCallable,
     *,
     message: Optional[str] = None,
     stacklevel: int = DEFAULT_STACK_LEVEL,
@@ -167,9 +175,15 @@ def deprecate_non_keyword_only_args(
     Custom messages can also be provided.
 
     Args:
-        warning_cls (type):
-            The specific deprecation warning class to use. This must be a
-            subclass of :py:exc:`DeprecationWarning`.
+        warning_cls (type or callable):
+            The type of warning class to use, or a callable returning one.
+
+            A callable can be used to avoid circular references.
+
+            Version Changed:
+                1.1:
+                This can now be either a warning class or a function
+                that returns one.
 
         message (str, optional):
             An optional message to use instead of the default.
@@ -402,7 +416,7 @@ def deprecate_non_keyword_only_args(
 
 
 def func_deprecated(
-    warning_cls: DeprecationWarningType,
+    warning_cls: DeprecationWarningTypeOrCallable,
     *,
     message: Optional[str] = None,
     stacklevel: int = DEFAULT_STACK_LEVEL,
@@ -424,8 +438,15 @@ def func_deprecated(
     Custom messages can also be provided.
 
     Args:
-        warning_cls (type):
-            The deprecation warning class to emit.
+        warning_cls (type or callable):
+            The type of warning class to use, or a callable returning one.
+
+            A callable can be used to avoid circular references.
+
+            Version Changed:
+                1.1:
+                This can now be either a warning class or a function
+                that returns one.
 
         message (str, optional):
             A custom message to display for the deprecation message.
@@ -477,7 +498,7 @@ def func_deprecated(
 
 
 def func_moved(
-    warning_cls: DeprecationWarningType,
+    warning_cls: DeprecationWarningTypeOrCallable,
     new_func: Union[str, Callable],
     *,
     message: Optional[str] = None,
@@ -501,8 +522,15 @@ def func_moved(
     Custom messages can also be provided.
 
     Args:
-        warning_cls (type):
-            The deprecation warning class to emit.
+        warning_cls (type or callable):
+            The type of warning class to use, or a callable returning one.
+
+            A callable can be used to avoid circular references.
+
+            Version Changed:
+                1.1:
+                This can now be either a warning class or a function
+                that returns one.
 
         new_func (str):
             The new function, or a descriptive string referencing the new
diff --git a/housekeeping/helpers.py b/housekeeping/helpers.py
index 3eccdd29585ae8d8cdea2a84dbdca0639ffa8218..9ffe969e15dc1d00d2df71a6be10820a9d9dfd5e 100644
--- a/housekeeping/helpers.py
+++ b/housekeeping/helpers.py
@@ -7,9 +7,11 @@ from __future__ import annotations
 
 import inspect
 import operator
+from types import FunctionType
 from typing import Any, Callable, Generic, Type, TypeVar, Union, cast
 
-from housekeeping.base import DEFAULT_STACK_LEVEL, DeprecationWarningType
+from housekeeping.base import (DEFAULT_STACK_LEVEL,
+                               DeprecationWarningTypeOrCallable)
 
 
 _T = TypeVar('_T')
@@ -189,7 +191,7 @@ def format_display_name(
 
 
 def emit_warning(
-    warning_cls: DeprecationWarningType,
+    warning_cls: DeprecationWarningTypeOrCallable,
     *,
     deprecation_msg: str,
     pending_deprecation_msg: str,
@@ -203,7 +205,7 @@ def emit_warning(
     class.
 
     Args:
-        warning_cls (type):
+        warning_cls (type or callable):
             The deprecation warning class.
 
         deprecation_msg (str):
@@ -223,6 +225,13 @@ def emit_warning(
     """
     message: str
 
+    if isinstance(warning_cls, FunctionType):
+        warning_cls = warning_cls()
+
+    if not inspect.isclass(warning_cls):
+        raise TypeError('Expected a deprecation warning class for %r'
+                        % warning_cls)
+
     if issubclass(warning_cls, DeprecationWarning):
         message = deprecation_msg
     elif issubclass(warning_cls, PendingDeprecationWarning):
diff --git a/housekeeping/modules.py b/housekeeping/modules.py
index aebb177bad3f0746bdd7380318319e1d52b577e2..41f94d043f220f1f0848352f4d24b42dc8ef67a8 100644
--- a/housekeeping/modules.py
+++ b/housekeeping/modules.py
@@ -4,12 +4,13 @@ from __future__ import annotations
 
 from typing import Optional
 
-from housekeeping.base import DEFAULT_STACK_LEVEL, DeprecationWarningType
+from housekeeping.base import (DEFAULT_STACK_LEVEL,
+                               DeprecationWarningTypeOrCallable)
 from housekeeping.helpers import emit_warning
 
 
 def module_deprecated(
-    warning_cls: DeprecationWarningType,
+    warning_cls: DeprecationWarningTypeOrCallable,
     module_name: str,
     *,
     message: Optional[str] = None,
@@ -32,7 +33,14 @@ def module_deprecated(
 
     Args:
         warning_cls (type, optional):
-            The type of warning class to use.
+            The type of warning class to use, or a callable returning one.
+
+            A callable can be used to avoid circular references.
+
+            Version Changed:
+                1.1:
+                This can now be either a warning class or a function
+                that returns one.
 
         module_name (str):
             The name of the deprecated module.
@@ -62,7 +70,7 @@ def module_deprecated(
 
 
 def module_moved(
-    warning_cls: DeprecationWarningType,
+    warning_cls: DeprecationWarningTypeOrCallable,
     old_module_name: str,
     new_module_name: str,
     *,
@@ -86,7 +94,14 @@ def module_moved(
 
     Args:
         warning_cls (type, optional):
-            The type of warning class to use.
+            The type of warning class to use, or a callable returning one.
+
+            A callable can be used to avoid circular references.
+
+            Version Changed:
+                1.1:
+                This can now be either a warning class or a function
+                that returns one.
 
         old_module_name (str):
             The name of the deprecated module.
diff --git a/housekeeping/tests/test_classes.py b/housekeeping/tests/test_classes.py
index 7ccab1aef90526c5de0673b056cbf1ef871c3eb3..1f58652ba5bab2b0e1d022df70676f5b9828fb55 100644
--- a/housekeeping/tests/test_classes.py
+++ b/housekeeping/tests/test_classes.py
@@ -45,6 +45,25 @@ class ClassDeprecatedMixinTests(TestCase):
             class MySubclass(MyOldClass):
                 pass
 
+    def test_subclass_with_warning_cls_callable(self) -> None:
+        """Testing ClassDeprecatedMixin subclassing with warning_cls as
+        callable
+        """
+        class MyOldClass(ClassDeprecatedMixin,
+                         warning_cls=lambda: MyRemovedInWarning):
+            pass
+
+        prefix = self.locals_prefix
+        message = (
+            f'`{prefix}.MySubclass` subclasses `{prefix}.MyOldClass`, which '
+            f'is deprecated and will be removed in My Product 1.0.'
+        )
+        line = 'class MySubclass(MyOldClass):'
+
+        with self.assertWarning(MyRemovedInWarning, message, line):
+            class MySubclass(MyOldClass):
+                pass
+
     def test_subclass_with_deprecation_msg(self) -> None:
         """Testing ClassDeprecatedMixin subclassing with deprecation and
         subclass_deprecation_msg=
@@ -211,6 +230,27 @@ class ClassMovedMixinTests(TestCase):
             class MySubclass(MyOldClass):
                 pass
 
+    def test_subclass_with_warning_cls_callable(self) -> None:
+        """Testing ClassMovedMixin subclassing with warning_cls as callable"""
+        class MyNewClass:
+            pass
+
+        class MyOldClass(ClassMovedMixin, MyNewClass,
+                         warning_cls=lambda: MyPendingRemovalWarning):
+            pass
+
+        prefix = self.locals_prefix
+        message = (
+            f'`{prefix}.MySubclass` subclasses `{prefix}.MyOldClass`, which '
+            f'is scheduled to be deprecated in a future version of My '
+            f'Product. To prepare, subclass `{prefix}.MyNewClass` instead.'
+        )
+        line = 'class MySubclass(MyOldClass):'
+
+        with self.assertWarning(MyPendingRemovalWarning, message, line):
+            class MySubclass(MyOldClass):
+                pass
+
     def test_subclass_with_deprecation_msg(self) -> None:
         """Testing ClassMovedMixin subclassing with subclass_deprecation_msg=
         """
diff --git a/housekeeping/tests/test_functions.py b/housekeeping/tests/test_functions.py
index 2cd401f3683d7f7f844cb1afb309ca44d938ecdb..93eef20f3a50d04b969e28bbe284329b49b5c0f7 100644
--- a/housekeeping/tests/test_functions.py
+++ b/housekeeping/tests/test_functions.py
@@ -33,6 +33,25 @@ class DeprecatedArgValueTests(TestCase):
 
         self.assertEqual(result, 124)
 
+    def test_with_warning_cls_as_callable(self) -> None:
+        """Testing deprecated_arg_value with warning_cls as callable"""
+        value = deprecated_arg_value(
+            lambda: MyRemovedInWarning,
+            owner_name='my_func()',
+            value=123,
+            old_name='old_arg')
+
+        message = (
+            '`old_arg` for `my_func()` has been deprecated and will be '
+            'removed in My Product 1.0.'
+        )
+        line = 'result = 1 + value'
+
+        with self.assertWarning(MyRemovedInWarning, message, line):
+            result = 1 + value
+
+        self.assertEqual(result, 124)
+
 
 class DeprecateNonKeywordOnlyArgsTests(TestCase):
     """Unit tests for @deprecate_non_keyword_only_args."""
@@ -172,6 +191,27 @@ class DeprecateNonKeywordOnlyArgsTests(TestCase):
 
         self.assertEqual(result, 6)
 
+    def test_with_warning_cls_callable(self) -> None:
+        """Testing @deprecate_non_keyword_only_args with warning_cls as
+        callable
+        """
+        @deprecate_non_keyword_only_args(lambda: MyRemovedInWarning)
+        def my_func(a, *, b, c=1):
+            return a + b + c
+
+        prefix = self.locals_prefix
+        message = (
+            f'Positional argument `b` must be passed as a keyword argument '
+            f'when calling `{prefix}.my_func()`. Passing as a positional '
+            f'argument will be required in My Product 1.0.'
+        )
+        line = 'result = my_func(1, 2, c=3)  # type: ignore'
+
+        with self.assertWarning(MyRemovedInWarning, message, line):
+            result = my_func(1, 2, c=3)  # type: ignore
+
+        self.assertEqual(result, 6)
+
 
 class FuncDeprecatedTests(TestCase):
     """Unit tests for func_deprecated."""
@@ -262,6 +302,24 @@ class FuncDeprecatedTests(TestCase):
 
         self.assertEqual(result, 3)
 
+    def test_with_warning_cls_callable(self) -> None:
+        """Testing @func_deprecated with warning_cls as callable"""
+        @func_deprecated(lambda: MyRemovedInWarning)
+        def my_func(a, b):
+            return a + b
+
+        prefix = self.locals_prefix
+        message = (
+            f'`{prefix}.my_func()` is deprecated and will be removed in My '
+            f'Product 1.0.'
+        )
+        line = 'result = my_func(1, 2)'
+
+        with self.assertWarning(MyRemovedInWarning, message, line):
+            result = my_func(1, 2)
+
+        self.assertEqual(result, 3)
+
 
 class FuncMovedTests(TestCase):
     """Unit tests for func_moved."""
@@ -401,3 +459,22 @@ class FuncMovedTests(TestCase):
             result = my_func(1, 2)
 
         self.assertEqual(result, 3)
+
+    def test_with_warning_cls_callable(self) -> None:
+        """Testing @func_moved with warning_cls as callable"""
+        @func_moved(lambda: MyRemovedInWarning,
+                    'my_new_func')
+        def my_func(a, b):
+            return a + b
+
+        prefix = self.locals_prefix
+        message = (
+            f'`{prefix}.my_func()` has moved to `my_new_func()`. The old '
+            f'function is deprecated and will be removed in My Product 1.0.'
+        )
+        line = 'result = my_func(1, 2)'
+
+        with self.assertWarning(MyRemovedInWarning, message, line):
+            result = my_func(1, 2)
+
+        self.assertEqual(result, 3)
diff --git a/housekeeping/tests/test_modules.py b/housekeeping/tests/test_modules.py
index af13ccbd2623b9a6c99ef6ab27bf47a5b7674450..74e0e65df0f4f2e00f4913dd30cf04810d14148f 100644
--- a/housekeeping/tests/test_modules.py
+++ b/housekeeping/tests/test_modules.py
@@ -58,6 +58,20 @@ class ModuleDeprecatedTests(TestCase):
                                 '_import_module()'):
             _import_module()
 
+    def test_with_warning_cls_callable(self) -> None:
+        """Testing module_deprecated and warning_cls as callable"""
+        def _import_module():
+            module_deprecated(lambda: MyRemovedInWarning, __name__)
+
+        message = (
+            '`housekeeping.tests.test_modules` is deprecated and will be '
+            'removed in My Product 1.0.'
+        )
+
+        with self.assertWarning(MyRemovedInWarning, message,
+                                '_import_module()'):
+            _import_module()
+
 
 class ModuleMovedTests(TestCase):
     """Unit tests for module_moved."""
@@ -111,3 +125,17 @@ class ModuleMovedTests(TestCase):
         with self.assertWarning(MyRemovedInWarning, message,
                                 '_import_module()'):
             _import_module()
+
+    def test_with_warning_cls_callable(self) -> None:
+        """Testing module_moved and warning_cls as callable"""
+        def _import_module():
+            module_moved(lambda: MyRemovedInWarning, __name__, 'my.new.module')
+
+        message = (
+            '`housekeeping.tests.test_modules` is deprecated and will be '
+            'removed in My Product 1.0. Import `my.new.module` instead.'
+        )
+
+        with self.assertWarning(MyRemovedInWarning, message,
+                                '_import_module()'):
+            _import_module()
