diff --git a/homeassistant/components/dsmr_reader/definitions.py b/homeassistant/components/dsmr_reader/definitions.py
index 9003c4d4334d40d1b5b477a4bd932d829c9f9fab..62d095aa993ff1949fe7d41022fedec53696246b 100644
--- a/homeassistant/components/dsmr_reader/definitions.py
+++ b/homeassistant/components/dsmr_reader/definitions.py
@@ -40,6 +40,7 @@ def tariff_transform(value: str) -> str:
 
 
 @dataclass(frozen=True)
+# pylint: disable-next=hass-enforce-class-module
 class DSMRReaderSensorEntityDescription(SensorEntityDescription):
     """Sensor entity description for DSMR Reader."""
 
diff --git a/homeassistant/components/growatt_server/sensor_types/sensor_entity_description.py b/homeassistant/components/growatt_server/sensor_types/sensor_entity_description.py
index e1ee4c303267a9887bc3b1a2307c475fc46eafe2..10d00671ba52a4aab9288e58c0e189f45ffe77dd 100644
--- a/homeassistant/components/growatt_server/sensor_types/sensor_entity_description.py
+++ b/homeassistant/components/growatt_server/sensor_types/sensor_entity_description.py
@@ -15,6 +15,7 @@ class GrowattRequiredKeysMixin:
 
 
 @dataclass(frozen=True)
+# pylint: disable-next=hass-enforce-class-module
 class GrowattSensorEntityDescription(SensorEntityDescription, GrowattRequiredKeysMixin):
     """Describes Growatt sensor entity."""
 
diff --git a/homeassistant/components/repetier/__init__.py b/homeassistant/components/repetier/__init__.py
index 2642e78e7ec0b2be1b66a7b33e4b59440e176441..27ddc62a8471042a9e8ff46b94f0bd8e5df4e4d1 100644
--- a/homeassistant/components/repetier/__init__.py
+++ b/homeassistant/components/repetier/__init__.py
@@ -133,6 +133,7 @@ class RepetierRequiredKeysMixin:
 
 
 @dataclass(frozen=True)
+# pylint: disable-next=hass-enforce-class-module
 class RepetierSensorEntityDescription(
     SensorEntityDescription, RepetierRequiredKeysMixin
 ):
diff --git a/homeassistant/components/sunweg/sensor_types/sensor_entity_description.py b/homeassistant/components/sunweg/sensor_types/sensor_entity_description.py
index 8c792ab617fd8cb5b809dc10af76b7f99691c140..1d06f04ab3d4dc41c11805c275541ac855dfe387 100644
--- a/homeassistant/components/sunweg/sensor_types/sensor_entity_description.py
+++ b/homeassistant/components/sunweg/sensor_types/sensor_entity_description.py
@@ -15,6 +15,7 @@ class SunWEGRequiredKeysMixin:
 
 
 @dataclass(frozen=True)
+# pylint: disable-next=hass-enforce-class-module
 class SunWEGSensorEntityDescription(SensorEntityDescription, SunWEGRequiredKeysMixin):
     """Describes SunWEG sensor entity."""
 
diff --git a/pylint/plugins/hass_enforce_class_module.py b/pylint/plugins/hass_enforce_class_module.py
index d9f844f907f0e4eae0c5cbf2d2b6a9506ce80540..dcd42f9a1c16c78c2c2aaf5a5c9fec6315f31ef7 100644
--- a/pylint/plugins/hass_enforce_class_module.py
+++ b/pylint/plugins/hass_enforce_class_module.py
@@ -1,38 +1,91 @@
-"""Plugin for checking if coordinator is in its own module."""
+"""Plugin for checking if class is in correct module."""
 
 from __future__ import annotations
 
+from ast import ClassDef
+from dataclasses import dataclass
+
 from astroid import nodes
 from pylint.checkers import BaseChecker
 from pylint.lint import PyLinter
 
 
+@dataclass
+class ClassModuleMatch:
+    """Class for pattern matching."""
+
+    expected_module: str
+    base_class: str
+
+
+_MODULES = [
+    ClassModuleMatch("alarm_control_panel", "AlarmControlPanelEntityDescription"),
+    ClassModuleMatch("assist_satellite", "AssistSatelliteEntityDescription"),
+    ClassModuleMatch("binary_sensor", "BinarySensorEntityDescription"),
+    ClassModuleMatch("button", "ButtonEntityDescription"),
+    ClassModuleMatch("camera", "CameraEntityDescription"),
+    ClassModuleMatch("climate", "ClimateEntityDescription"),
+    ClassModuleMatch("coordinator", "DataUpdateCoordinator"),
+    ClassModuleMatch("cover", "CoverEntityDescription"),
+    ClassModuleMatch("date", "DateEntityDescription"),
+    ClassModuleMatch("datetime", "DateTimeEntityDescription"),
+    ClassModuleMatch("event", "EventEntityDescription"),
+    ClassModuleMatch("image", "ImageEntityDescription"),
+    ClassModuleMatch("image_processing", "ImageProcessingEntityDescription"),
+    ClassModuleMatch("lawn_mower", "LawnMowerEntityDescription"),
+    ClassModuleMatch("lock", "LockEntityDescription"),
+    ClassModuleMatch("media_player", "MediaPlayerEntityDescription"),
+    ClassModuleMatch("notify", "NotifyEntityDescription"),
+    ClassModuleMatch("number", "NumberEntityDescription"),
+    ClassModuleMatch("select", "SelectEntityDescription"),
+    ClassModuleMatch("sensor", "SensorEntityDescription"),
+    ClassModuleMatch("text", "TextEntityDescription"),
+    ClassModuleMatch("time", "TimeEntityDescription"),
+    ClassModuleMatch("update", "UpdateEntityDescription"),
+    ClassModuleMatch("vacuum", "VacuumEntityDescription"),
+    ClassModuleMatch("water_heater", "WaterHeaterEntityDescription"),
+    ClassModuleMatch("weather", "WeatherEntityDescription"),
+]
+
+
 class HassEnforceClassModule(BaseChecker):
-    """Checker for coordinators own module."""
+    """Checker for class in correct module."""
 
     name = "hass_enforce_class_module"
     priority = -1
     msgs = {
         "C7461": (
-            "Derived data update coordinator is recommended to be placed in the 'coordinator' module",
+            "Derived %s is recommended to be placed in the '%s' module",
             "hass-enforce-class-module",
-            "Used when derived data update coordinator should be placed in its own module.",
+            "Used when derived class should be placed in its own module.",
         ),
     }
 
     def visit_classdef(self, node: nodes.ClassDef) -> None:
-        """Check if derived data update coordinator is placed in its own module."""
+        """Check if derived class is placed in its own module."""
         root_name = node.root().name
 
-        # we only want to check component update coordinators
-        if not root_name.startswith("homeassistant.components"):
+        # we only want to check components
+        if not root_name.startswith("homeassistant.components."):
             return
 
-        is_coordinator_module = root_name.endswith(".coordinator")
-        for ancestor in node.ancestors():
-            if ancestor.name == "DataUpdateCoordinator" and not is_coordinator_module:
-                self.add_message("hass-enforce-class-module", node=node)
-                return
+        ancestors: list[ClassDef] | None = None
+
+        for match in _MODULES:
+            if root_name.endswith(f".{match.expected_module}"):
+                continue
+
+            if ancestors is None:
+                ancestors = list(node.ancestors())  # cache result for other modules
+
+            for ancestor in ancestors:
+                if ancestor.name == match.base_class:
+                    self.add_message(
+                        "hass-enforce-class-module",
+                        node=node,
+                        args=(match.base_class, match.expected_module),
+                    )
+                    return
 
 
 def register(linter: PyLinter) -> None:
diff --git a/tests/pylint/conftest.py b/tests/pylint/conftest.py
index 38b4188230f1c5e043ae845b2a9bac86d84e437c..5e8ed28da6b477258c02808e5dd023a376069c5a 100644
--- a/tests/pylint/conftest.py
+++ b/tests/pylint/conftest.py
@@ -113,13 +113,11 @@ def hass_enforce_class_module_fixture() -> ModuleType:
     )
 
 
-@pytest.fixture(name="enforce_coordinator_module_checker")
-def enforce_coordinator_module_fixture(
-    hass_enforce_class_module, linter
-) -> BaseChecker:
+@pytest.fixture(name="enforce_class_module_checker")
+def enforce_class_module_fixture(hass_enforce_class_module, linter) -> BaseChecker:
     """Fixture to provide a hass_enforce_class_module checker."""
-    enforce_coordinator_module_checker = (
-        hass_enforce_class_module.HassEnforceClassModule(linter)
+    enforce_class_module_checker = hass_enforce_class_module.HassEnforceClassModule(
+        linter
     )
-    enforce_coordinator_module_checker.module = "homeassistant.components.pylint_test"
-    return enforce_coordinator_module_checker
+    enforce_class_module_checker.module = "homeassistant.components.pylint_test"
+    return enforce_class_module_checker
diff --git a/tests/pylint/test_enforce_class_module.py b/tests/pylint/test_enforce_class_module.py
index 5fd6e0e88ccd29737026b1481b3515863a76d2fa..b0f071fde52e209dc8abd955cd4bf2392c6776d9 100644
--- a/tests/pylint/test_enforce_class_module.py
+++ b/tests/pylint/test_enforce_class_module.py
@@ -41,21 +41,21 @@ from . import assert_adds_messages, assert_no_messages
         ),
     ],
 )
-def test_enforce_coordinator_module_good(
-    linter: UnittestLinter, enforce_coordinator_module_checker: BaseChecker, code: str
+def test_enforce_class_module_good(
+    linter: UnittestLinter, enforce_class_module_checker: BaseChecker, code: str
 ) -> None:
     """Good test cases."""
     root_node = astroid.parse(code, "homeassistant.components.pylint_test.coordinator")
     walker = ASTWalker(linter)
-    walker.add_checker(enforce_coordinator_module_checker)
+    walker.add_checker(enforce_class_module_checker)
 
     with assert_no_messages(linter):
         walker.walk(root_node)
 
 
-def test_enforce_coordinator_module_bad_simple(
+def test_enforce_class_module_bad_simple(
     linter: UnittestLinter,
-    enforce_coordinator_module_checker: BaseChecker,
+    enforce_class_module_checker: BaseChecker,
 ) -> None:
     """Bad test case with coordinator extending directly."""
     root_node = astroid.parse(
@@ -69,7 +69,7 @@ def test_enforce_coordinator_module_bad_simple(
         "homeassistant.components.pylint_test",
     )
     walker = ASTWalker(linter)
-    walker.add_checker(enforce_coordinator_module_checker)
+    walker.add_checker(enforce_class_module_checker)
 
     with assert_adds_messages(
         linter,
@@ -77,7 +77,7 @@ def test_enforce_coordinator_module_bad_simple(
             msg_id="hass-enforce-class-module",
             line=5,
             node=root_node.body[1],
-            args=None,
+            args=("DataUpdateCoordinator", "coordinator"),
             confidence=UNDEFINED,
             col_offset=0,
             end_line=5,
@@ -87,9 +87,9 @@ def test_enforce_coordinator_module_bad_simple(
         walker.walk(root_node)
 
 
-def test_enforce_coordinator_module_bad_nested(
+def test_enforce_class_module_bad_nested(
     linter: UnittestLinter,
-    enforce_coordinator_module_checker: BaseChecker,
+    enforce_class_module_checker: BaseChecker,
 ) -> None:
     """Bad test case with nested coordinators."""
     root_node = astroid.parse(
@@ -106,7 +106,7 @@ def test_enforce_coordinator_module_bad_nested(
         "homeassistant.components.pylint_test",
     )
     walker = ASTWalker(linter)
-    walker.add_checker(enforce_coordinator_module_checker)
+    walker.add_checker(enforce_class_module_checker)
 
     with assert_adds_messages(
         linter,
@@ -114,7 +114,7 @@ def test_enforce_coordinator_module_bad_nested(
             msg_id="hass-enforce-class-module",
             line=5,
             node=root_node.body[1],
-            args=None,
+            args=("DataUpdateCoordinator", "coordinator"),
             confidence=UNDEFINED,
             col_offset=0,
             end_line=5,
@@ -124,7 +124,7 @@ def test_enforce_coordinator_module_bad_nested(
             msg_id="hass-enforce-class-module",
             line=8,
             node=root_node.body[2],
-            args=None,
+            args=("DataUpdateCoordinator", "coordinator"),
             confidence=UNDEFINED,
             col_offset=0,
             end_line=8,