diff --git a/pyproject.toml b/pyproject.toml
index 5d8b689e2..c7e678b51 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -102,6 +102,8 @@ warn_unused_ignores = true
 module = [
     "*.hatchling.*",
     "*.hatch.utils.*",
+    "hatch.plugin.*",
+    "hatch.template.*",
 ]
 disallow_untyped_defs = true
 disallow_incomplete_defs = true
diff --git a/src/hatch/plugin/manager.py b/src/hatch/plugin/manager.py
index aa02983ea..e2b93856c 100644
--- a/src/hatch/plugin/manager.py
+++ b/src/hatch/plugin/manager.py
@@ -2,29 +2,29 @@
 
 
 class PluginManager(_PluginManager):
-    def initialize(self):
+    def initialize(self) -> None:
         super().initialize()
 
         from hatch.plugin import specs
 
         self.manager.add_hookspecs(specs)
 
-    def hatch_register_environment(self):
+    def hatch_register_environment(self) -> None:
         from hatch.env.plugin import hooks
 
         self.manager.register(hooks)
 
-    def hatch_register_environment_collector(self):
+    def hatch_register_environment_collector(self) -> None:
         from hatch.env.collectors.plugin import hooks
 
         self.manager.register(hooks)
 
-    def hatch_register_publisher(self):
+    def hatch_register_publisher(self) -> None:
         from hatch.publish.plugin import hooks
 
         self.manager.register(hooks)
 
-    def hatch_register_template(self):
+    def hatch_register_template(self) -> None:
         from hatch.template.plugin import hooks
 
         self.manager.register(hooks)
diff --git a/src/hatch/plugin/specs.py b/src/hatch/plugin/specs.py
index 8a5d83b74..87da53283 100644
--- a/src/hatch/plugin/specs.py
+++ b/src/hatch/plugin/specs.py
@@ -2,25 +2,25 @@
 
 
 @hookspec
-def hatch_register_environment():
+def hatch_register_environment() -> None:
     """Register new classes that adhere to the environment interface."""
 
 
 @hookspec
-def hatch_register_environment_collector():
+def hatch_register_environment_collector() -> None:
     """Register new classes that adhere to the environment collector interface."""
 
 
 @hookspec
-def hatch_register_version_scheme():
+def hatch_register_version_scheme() -> None:
     """Register new classes that adhere to the version scheme interface."""
 
 
 @hookspec
-def hatch_register_publisher():
+def hatch_register_publisher() -> None:
     """Register new classes that adhere to the publisher interface."""
 
 
 @hookspec
-def hatch_register_template():
+def hatch_register_template() -> None:
     """Register new classes that adhere to the template interface."""
diff --git a/src/hatch/template/__init__.py b/src/hatch/template/__init__.py
index d1008812a..df62bc944 100644
--- a/src/hatch/template/__init__.py
+++ b/src/hatch/template/__init__.py
@@ -1,9 +1,11 @@
 from __future__ import annotations
 
 from contextlib import suppress
-from typing import TYPE_CHECKING
+from typing import TYPE_CHECKING, Generator
 
 if TYPE_CHECKING:
+    from types import ModuleType
+
     from hatch.utils.fs import Path
 
 
@@ -13,7 +15,7 @@ def __init__(self, path: Path | None, contents: str = ''):
         self.contents = contents
         self.feature = None
 
-    def write(self, root):
+    def write(self, root: Path) -> None:
         if self.path is None:  # no cov
             return
 
@@ -22,7 +24,7 @@ def write(self, root):
         path.write_text(self.contents, encoding='utf-8')
 
 
-def find_template_files(module):
+def find_template_files(module: ModuleType) -> Generator[File, None, None]:
     for name in dir(module):
         obj = getattr(module, name)
         if obj is File:
diff --git a/src/hatch/template/default.py b/src/hatch/template/default.py
index 71acb3e97..a06ef0043 100644
--- a/src/hatch/template/default.py
+++ b/src/hatch/template/default.py
@@ -1,25 +1,32 @@
+from __future__ import annotations
+
+from typing import TYPE_CHECKING, Any
+
 from hatch.template import File, files_default, find_template_files
 from hatch.template.plugin.interface import TemplateInterface
 from hatch.utils.fs import Path
 from hatch.utils.network import download_file
 
+if TYPE_CHECKING:
+    from datetime import datetime
+
 
 class DefaultTemplate(TemplateInterface):
     PLUGIN_NAME = 'default'
 
-    def __init__(self, *args, **kwargs):
+    def __init__(self, *args: Any, **kwargs: Any) -> None:
         super().__init__(*args, **kwargs)
 
         self.plugin_config.setdefault('ci', False)
         self.plugin_config.setdefault('src-layout', True)
         self.plugin_config.setdefault('tests', True)
 
-    def initialize_config(self, config):
+    def initialize_config(self, config: dict) -> None:
         # Default values
         config['readme_file_path'] = 'README.md'
         config['package_metadata_file_path'] = f'src/{config["package_name"]}/__about__.py'
 
-        license_data = {}
+        license_data: dict[str, str] = {}
 
         # Licenses
         license_ids = config['licenses']['default']
@@ -73,7 +80,7 @@ def initialize_config(self, config):
         if not self.plugin_config['src-layout']:
             config['package_metadata_file_path'] = f'{config["package_metadata_file_path"][4:]}'
 
-    def get_files(self, config):
+    def get_files(self, config: dict) -> list[File]:
         files = list(find_template_files(files_default))
 
         # Add any licenses
@@ -106,19 +113,19 @@ def get_files(self, config):
 
         return files
 
-    def finalize_files(self, config, files):
+    def finalize_files(self, config: dict, files: list[File]) -> None:
         if config['licenses']['headers'] and config['license_data']:
             for template_file in files:
-                if template_file.path.name.endswith('.py'):
+                if template_file.path and template_file.path.name.endswith('.py'):
                     template_file.contents = config['license_header'] + template_file.contents
 
         if self.plugin_config['src-layout']:
             for template_file in files:
-                if template_file.path.parts[0] == config['package_name']:
+                if template_file.path and template_file.path.parts[0] == config['package_name']:
                     template_file.path = Path('src', template_file.path)
 
 
-def get_license_text(config, license_id, license_text, creation_time):
+def get_license_text(config: dict, license_id: str, license_text: str, creation_time: datetime) -> str:
     if license_id == 'MIT':
         license_text = license_text.replace('<year>', f'{creation_time.year}-present', 1)
         license_text = license_text.replace('<copyright holders>', f'{config["name"]} <{config["email"]}>', 1)
diff --git a/src/hatch/template/plugin/hooks.py b/src/hatch/template/plugin/hooks.py
index 08953b50d..8336cab3d 100644
--- a/src/hatch/template/plugin/hooks.py
+++ b/src/hatch/template/plugin/hooks.py
@@ -1,7 +1,14 @@
+from __future__ import annotations
+
+from typing import TYPE_CHECKING
+
 from hatch.template.default import DefaultTemplate
 from hatchling.plugin import hookimpl
 
+if TYPE_CHECKING:
+    from hatch.template.plugin.interface import TemplateInterface
+
 
 @hookimpl
-def hatch_register_template():
+def hatch_register_template() -> type[TemplateInterface]:
     return DefaultTemplate
diff --git a/src/hatch/template/plugin/interface.py b/src/hatch/template/plugin/interface.py
index 2a361c666..edd686e00 100644
--- a/src/hatch/template/plugin/interface.py
+++ b/src/hatch/template/plugin/interface.py
@@ -1,21 +1,32 @@
+from __future__ import annotations
+
+from typing import TYPE_CHECKING
+
+if TYPE_CHECKING:
+    from datetime import datetime
+
+    from hatch.template import File
+    from hatch.utils.fs import Path
+
+
 class TemplateInterface:
     PLUGIN_NAME = ''
     PRIORITY = 100
 
-    def __init__(self, plugin_config: dict, cache_dir, creation_time):
+    def __init__(self, plugin_config: dict, cache_dir: Path, creation_time: datetime) -> None:
         self.plugin_config = plugin_config
         self.cache_dir = cache_dir
         self.creation_time = creation_time
 
-    def initialize_config(self, config):
+    def initialize_config(self, config: dict) -> None:
         """
         Allow modification of the configuration passed to every file for new projects
         before the list of files are determined.
         """
 
-    def get_files(self, config):  # noqa: ARG002, PLR6301
+    def get_files(self, config: dict) -> list[File]:  # noqa: ARG002, PLR6301
         """Add to the list of files for new projects that are written to the file system."""
         return []
 
-    def finalize_files(self, config, files):
+    def finalize_files(self, config: dict, files: list[File]) -> None:
         """Allow modification of files for new projects before they are written to the file system."""