diff --git a/.github/workflows/hamilton-lsp.yml b/.github/workflows/hamilton-lsp.yml
index 83e17dc67..b1d23c224 100644
--- a/.github/workflows/hamilton-lsp.yml
+++ b/.github/workflows/hamilton-lsp.yml
@@ -17,7 +17,7 @@ jobs:
     runs-on: ubuntu-latest
     strategy:
       matrix:
-        python-version: ['3.9', '3.10', '3.11']
+        python-version: ['3.10', '3.11', '3.12', '3.13']
     defaults:
       run:
         working-directory: dev_tools/language_server
diff --git a/.github/workflows/hamilton-main.yml b/.github/workflows/hamilton-main.yml
index 15495039a..b1039c81c 100644
--- a/.github/workflows/hamilton-main.yml
+++ b/.github/workflows/hamilton-main.yml
@@ -23,11 +23,10 @@ jobs:
         os:
           - ubuntu-latest
         python-version:
-          - '3.8'
-          - '3.9'
           - '3.10'
           - '3.11'
           - '3.12'
+          - '3.13'
     env:
       UV_PRERELEASE: "allow"
       HAMILTON_TELEMETRY_ENABLED: false
diff --git a/.github/workflows/hamilton-sdk.yml b/.github/workflows/hamilton-sdk.yml
index 5ec89e5aa..d5f539f41 100644
--- a/.github/workflows/hamilton-sdk.yml
+++ b/.github/workflows/hamilton-sdk.yml
@@ -17,7 +17,7 @@ jobs:
     runs-on: ubuntu-latest
     strategy:
       matrix:
-        python-version: ['3.9', '3.10', '3.11']
+        python-version: ['3.10', '3.11', '3.12', '3.13']
     defaults:
       run:
         working-directory: ui/sdk
diff --git a/hamilton/cli/__main__.py b/hamilton/cli/__main__.py
index 41c411c6e..e5321bcb4 100644
--- a/hamilton/cli/__main__.py
+++ b/hamilton/cli/__main__.py
@@ -19,16 +19,10 @@
 import json
 import logging
 import os
-import sys
 import warnings
 from pathlib import Path
 from pprint import pprint
-from typing import Any, Callable, List, Optional
-
-if sys.version_info < (3, 9):
-    from typing_extensions import Annotated
-else:
-    from typing import Annotated
+from typing import Annotated, Any, Callable, List, Optional
 
 import typer
 
diff --git a/hamilton/htypes.py b/hamilton/htypes.py
index 6849ed56a..ad374243a 100644
--- a/hamilton/htypes.py
+++ b/hamilton/htypes.py
@@ -18,14 +18,10 @@
 import inspect
 import sys
 import typing
-from typing import Any, Iterable, Optional, Protocol, Tuple, Type, TypeVar, Union
+from typing import Any, Iterable, Literal, Optional, Protocol, Tuple, Type, TypeVar, Union
 
 import typing_inspect
 
-if sys.version_info >= (3, 9):
-    from typing import Literal
-else:
-    Literal = None
 from hamilton.registry import COLUMN_TYPE, DF_TYPE_AND_COLUMN_TYPES
 
 BASE_ARGS_FOR_GENERICS = (typing.T,)
diff --git a/hamilton/node.py b/hamilton/node.py
index 5a0ba3f56..36ffd6f21 100644
--- a/hamilton/node.py
+++ b/hamilton/node.py
@@ -118,8 +118,9 @@ def __init__(
                 # assume optional values passed
                 self._default_parameter_values = optional_values if optional_values else {}
             else:
-                # TODO -- remove this when we no longer support 3.8 -- 10/14/2024
-                type_hint_kwargs = {} if sys.version_info < (3, 9) else {"include_extras": True}
+                type_hint_kwargs: dict[str, Any] = {"include_extras": True}
+                if sys.version_info >= (3, 13):
+                    type_hint_kwargs["globalns"] = callabl.__globals__
                 input_types = typing.get_type_hints(callabl, **type_hint_kwargs)
                 signature = inspect.signature(callabl)
                 for key, value in signature.parameters.items():
@@ -291,8 +292,7 @@ def from_fn(fn: Callable, name: str = None) -> "Node":
         """
         if name is None:
             name = fn.__name__
-        # TODO -- remove this when we no longer support 3.8 -- 10/14/2024
-        type_hint_kwargs = {} if sys.version_info < (3, 9) else {"include_extras": True}
+        type_hint_kwargs = {"include_extras": True}
         return_type = typing.get_type_hints(fn, **type_hint_kwargs).get("return")
         if return_type is None:
             raise ValueError(f"Missing type hint for return value in function {fn.__qualname__}.")
diff --git a/hamilton/plugins/h_spark.py b/hamilton/plugins/h_spark.py
index 3d0f7e33a..ae494319e 100644
--- a/hamilton/plugins/h_spark.py
+++ b/hamilton/plugins/h_spark.py
@@ -18,7 +18,6 @@
 import functools
 import inspect
 import logging
-import sys
 from types import CodeType, FunctionType, ModuleType
 from typing import Any, Callable, Collection, Dict, List, Optional, Set, Tuple, Type, Union
 
@@ -229,10 +228,7 @@ def python_to_spark_type(python_type: Type[Union[int, float, bool, str, bytes]])
         raise ValueError("Unsupported Python type: " + str(python_type))
 
 
-if sys.version_info < (3, 9):
-    _list = (List[int], List[float], List[bool], List[str], List[bytes])
-else:
-    _list = (list[int], list[float], list[bool], list[str], list[bytes])
+_list = (list[int], list[float], list[bool], list[str], list[bytes])
 
 
 def get_spark_type(return_type: Any) -> types.DataType:
diff --git a/plugin_tests/h_spark/test_h_spark.py b/plugin_tests/h_spark/test_h_spark.py
index 0fcb44567..8a36d5ab4 100644
--- a/plugin_tests/h_spark/test_h_spark.py
+++ b/plugin_tests/h_spark/test_h_spark.py
@@ -15,7 +15,6 @@
 # specific language governing permissions and limitations
 # under the License.
 
-import sys
 
 import numpy as np
 import pandas as pd
@@ -356,7 +355,6 @@ def test_get_spark_type_basic_types(return_type, expected_spark_type):
 
 
 # 2. Lists of basic Python types
-@pytest.mark.skipif(sys.version_info < (3, 9), reason="requires python 3.9 or higher")
 @pytest.mark.parametrize(
     "return_type,expected_spark_type",
     [
diff --git a/pyproject.toml b/pyproject.toml
index 2e58e897e..bfa3f85e7 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -26,7 +26,7 @@ version = "1.89.0"  # NOTE: keep this in sync with hamilton/version.py
 # dynamic = ["version"]
 description = "Hamilton, the micro-framework for creating dataframes."
 readme = "README.md"
-requires-python = ">=3.8.1, <4"
+requires-python = ">=3.10.1, <4"
 license = {text = "Apache-2.0"}
 keywords = ["hamilton"]
 authors = [
@@ -39,11 +39,10 @@ classifiers = [
     "Natural Language :: English",
     "License :: OSI Approved :: Apache Software License",
     "Programming Language :: Python :: 3",
-    "Programming Language :: Python :: 3.8",
-    "Programming Language :: Python :: 3.9",
     "Programming Language :: Python :: 3.10",
     "Programming Language :: Python :: 3.11",
     "Programming Language :: Python :: 3.12",
+    "Programming Language :: Python :: 3.13"
 ]
 dependencies = [
     "numpy",
diff --git a/tests/function_modifiers/test_adapters.py b/tests/function_modifiers/test_adapters.py
index e95311a41..56052d5b5 100644
--- a/tests/function_modifiers/test_adapters.py
+++ b/tests/function_modifiers/test_adapters.py
@@ -711,14 +711,8 @@ def fn(data1: dict, data2: dict) -> dict:
     assert len(fg) == 5
 
 
-import sys
-
-if sys.version_info >= (3, 9):
-    dict_ = dict
-    tuple_ = tuple
-else:
-    dict_ = Dict
-    tuple_ = Tuple
+dict_ = dict
+tuple_ = tuple
 
 
 # Mock functions for dataloader & datasaver testing
@@ -770,10 +764,6 @@ def test_dl_validate_incorrect_functions(func):
         dl.validate(func)
 
 
-@pytest.mark.skipif(
-    sys.version_info < (3, 9, 0),
-    reason="dataloader not guarenteed to work with subscripted tuples on 3.8",
-)
 def test_dl_validate_with_correct_function():
     dl = dataloader()
     try:
diff --git a/tests/function_modifiers/test_expanders.py b/tests/function_modifiers/test_expanders.py
index ee9d1b17a..bbc2fef2c 100644
--- a/tests/function_modifiers/test_expanders.py
+++ b/tests/function_modifiers/test_expanders.py
@@ -38,10 +38,6 @@
 
 # TODO: Move/refactor for more general use
 skipif = pytest.mark.skipif
-prior_to_py39 = {
-    "condition": sys.version_info < (3, 9, 0),
-    "reason": "Python 3.9+ required for this test",
-}
 prior_to_py311 = {
     "condition": sys.version_info < (3, 11, 0),
     "reason": "Python 3.11+ required for this test",
@@ -377,9 +373,9 @@ class MyDictInheritanceBadCase(TypedDict):
         ("MyDict", ()),
         ("MyDict", {"test2": str}),
         ("MyDictInheritance", {"test": InheritedObject}),
-        pytest.param("dict[str, int]", ("A", "B"), marks=skipif(**prior_to_py39)),
-        pytest.param("dict[str, int]", (["A", "B"]), marks=skipif(**prior_to_py39)),
-        pytest.param("dict", {"A": str, "B": int}, marks=skipif(**prior_to_py39)),
+        ("dict[str, int]", ("A", "B")),
+        ("dict[str, int]", (["A", "B"])),
+        ("dict", {"A": str, "B": int}),
     ],
 )
 def test_extract_fields_valid_annotations_for_inferred_types(return_type_str, fields):
@@ -408,10 +404,10 @@ def function() -> return_type:  # type: ignore
         ("pd.DataFrame", {"A": int}),
         ("MyDictBad", {"A": int}),
         ("MyDictInheritanceBadCase", {"A": SomeObject}),
-        pytest.param("dict", ("A", "B"), marks=skipif(**prior_to_py39)),
-        pytest.param("dict", (["A", "B"]), marks=skipif(**prior_to_py39)),
-        pytest.param("dict", (["A"]), marks=skipif(**prior_to_py39)),
-        pytest.param("dict", (["A", "B", "C"]), marks=skipif(**prior_to_py39)),
+        ("dict", ("A", "B")),
+        ("dict", (["A", "B"])),
+        ("dict", (["A"])),
+        ("dict", (["A", "B", "C"])),
     ],
 )
 def test_extract_fields_invalid_annotations_for_inferred_types(return_type_str, fields):
@@ -781,9 +777,9 @@ def dummy() -> Tuple[int, ...]:
         ("Tuple[int, int]", ("A", "B")),
         ("Tuple[int, int, str]", ("A", "B", "C")),
         ("Tuple[int, ...]", ("A", "B")),
-        pytest.param("tuple[int, int]", ("A", "B"), marks=skipif(**prior_to_py39)),
-        pytest.param("tuple[int, int, str]", ("A", "B", "C"), marks=skipif(**prior_to_py39)),
-        pytest.param("tuple[int, ...]", ("A", "B"), marks=skipif(**prior_to_py39)),
+        ("tuple[int, int]", ("A", "B")),
+        ("tuple[int, int, str]", ("A", "B", "C")),
+        ("tuple[int, ...]", ("A", "B")),
     ],
 )
 def test_unpack_fields_valid_type_annotations(return_type_str, fields):
@@ -807,11 +803,11 @@ def function() -> return_type:
         pytest.param("Tuple[...]", ("A", "B", "C"), marks=skipif(**prior_to_py311)),
         pytest.param("Tuple[int, int, ...]", ("A", "B"), marks=skipif(**prior_to_py311)),
         pytest.param("Tuple[..., int, int]", ("A", "B"), marks=skipif(**prior_to_py311)),
-        pytest.param("tuple", ("A",), marks=skipif(**prior_to_py39)),
-        pytest.param("tuple[int, int]", ("A", "B", "C"), marks=skipif(**prior_to_py39)),
-        pytest.param("tuple[...]", ("A", "B", "C"), marks=skipif(**prior_to_py39)),
-        pytest.param("tuple[int, int, ...]", ("A", "B"), marks=skipif(**prior_to_py39)),
-        pytest.param("tuple[..., int, int]", ("A", "B"), marks=skipif(**prior_to_py39)),
+        ("tuple", ("A",)),
+        ("tuple[int, int]", ("A", "B", "C")),
+        ("tuple[...]", ("A", "B", "C")),
+        ("tuple[int, int, ...]", ("A", "B")),
+        ("tuple[..., int, int]", ("A", "B")),
     ],
 )
 def test_unpack_fields_invalid_type_annotations(return_type_str, fields):
@@ -1112,9 +1108,7 @@ def foo(x: int) -> int:
         annotation.validate(foo)
 
 
-@pytest.mark.skipif(**prior_to_py39)
 def test_inject_misconfigured_param_untyped_generic_list():
-    # NOTE: Stricter typing rules for generics were introduced in Python 3.9.
     def foo(x: List) -> int:
         return sum(x)
 
diff --git a/tests/integrations/pandera/test_pandera_data_quality.py b/tests/integrations/pandera/test_pandera_data_quality.py
index ef346776a..ac1a91ed8 100644
--- a/tests/integrations/pandera/test_pandera_data_quality.py
+++ b/tests/integrations/pandera/test_pandera_data_quality.py
@@ -15,7 +15,6 @@
 # specific language governing permissions and limitations
 # under the License.
 
-import sys
 
 import dask.dataframe as dd
 import numpy as np
@@ -165,7 +164,6 @@ def foo() -> pd.DataFrame:
         h_pandera.check_output().get_validators(n)
 
 
-@pytest.mark.skipif(sys.version_info < (3, 9), reason="requires python3.9 or higher")
 def test_pandera_decorator_dask_df():
     """Validates that the function can be annotated with a dask dataframe type it'll work appropriately.
 
@@ -216,7 +214,6 @@ def foo(fail: bool = False) -> dd.DataFrame:
     assert not result_success.passes
 
 
-@pytest.mark.skipif(sys.version_info < (3, 9), reason="requires python3.9 or higher")
 @pytest.mark.xfail(
     reason="some weird import issue leads to key error in pandera, can't recreate outside of the series decorator"
 )
diff --git a/tests/plugins/test_dlt_extensions.py b/tests/plugins/test_dlt_extensions.py
index fa899fc7c..96795aaef 100644
--- a/tests/plugins/test_dlt_extensions.py
+++ b/tests/plugins/test_dlt_extensions.py
@@ -15,24 +15,15 @@
 # specific language governing permissions and limitations
 # under the License.
 
-import sys
 from pathlib import Path
 
-import pytest
-
-PY38_OR_BELOW = sys.version_info < (3, 9)
-pytestmark = pytest.mark.skipif(
-    PY38_OR_BELOW, reason="Breaks for python 3.8 and below due to backports dependency."
-)
-
-if not PY38_OR_BELOW:
-    import dlt
-    from dlt.destinations import filesystem
-
-    from hamilton.plugins.dlt_extensions import DltDestinationSaver, DltResourceLoader
-
+import dlt
 import pandas as pd
 import pyarrow as pa
+import pytest
+from dlt.destinations import filesystem
+
+from hamilton.plugins.dlt_extensions import DltDestinationSaver, DltResourceLoader
 
 
 def pandas_df():
diff --git a/tests/plugins/test_huggingface_extensions.py b/tests/plugins/test_huggingface_extensions.py
index 664ab1229..7b52446a1 100644
--- a/tests/plugins/test_huggingface_extensions.py
+++ b/tests/plugins/test_huggingface_extensions.py
@@ -16,11 +16,9 @@
 # under the License.
 
 import pathlib
-import sys
 
 import lancedb
 import numpy as np
-import pytest
 from datasets import Dataset, DatasetDict
 
 from hamilton.plugins import huggingface_extensions
@@ -59,7 +57,6 @@ def test_hfds_parquet_saver(tmp_path: pathlib.Path):
     assert saver.applies_to(Dataset)
 
 
-@pytest.mark.skipif(sys.version_info < (3, 9), reason="requires Python 3.9 or higher")
 def test_hfds_lancedb_saver(tmp_path: pathlib.Path):
     db_client = lancedb.connect(tmp_path / "lancedb")
     saver = huggingface_extensions.HuggingFaceDSLanceDBSaver(db_client, "test_table")
diff --git a/tests/plugins/test_mlflow_extension.py b/tests/plugins/test_mlflow_extension.py
index 8b89212b8..d98d3ed47 100644
--- a/tests/plugins/test_mlflow_extension.py
+++ b/tests/plugins/test_mlflow_extension.py
@@ -15,27 +15,16 @@
 # specific language governing permissions and limitations
 # under the License.
 
-import sys
 from pathlib import Path
 
-import pytest
-
-PY38_OR_BELOW = sys.version_info < (3, 9)
-pytestmark = pytest.mark.skipif(
-    PY38_OR_BELOW, reason="Breaks for python 3.8 and below due to backports dependency."
-)
-
-if not PY38_OR_BELOW:
-    import mlflow
-
-    from hamilton.plugins.mlflow_extensions import MLFlowModelLoader, MLFlowModelSaver
-
+import mlflow
 import numpy as np
 import pytest
 from sklearn.base import BaseEstimator
 from sklearn.linear_model import LinearRegression
 
 from hamilton.io.materialization import from_, to
+from hamilton.plugins.mlflow_extensions import MLFlowModelLoader, MLFlowModelSaver
 
 # TODO move these tests to `plugin_tests` because the required read-writes can get
 # complicated and tests are time consuming.
diff --git a/tests/resources/nodes_with_future_annotation.py b/tests/resources/nodes_with_future_annotation.py
index f74ede77f..c577e80d7 100644
--- a/tests/resources/nodes_with_future_annotation.py
+++ b/tests/resources/nodes_with_future_annotation.py
@@ -17,17 +17,11 @@
 
 from __future__ import annotations
 
-import sys
-from typing import List, Tuple
-
 from hamilton.function_modifiers import dataloader
 from hamilton.htypes import Collect, Parallelizable
 
 """Tests future annotations with common node types"""
 
-tuple_ = Tuple if sys.version_info < (3, 9, 0) else tuple
-list_ = List if sys.version_info < (3, 9, 0) else list
-
 
 def parallelized() -> Parallelizable[int]:
     yield 1
@@ -44,6 +38,6 @@ def collected(standard: Collect[int]) -> int:
 
 
 @dataloader()
-def sample_dataloader() -> tuple_[list_[str], dict]:
+def sample_dataloader() -> tuple[list[str], dict]:
     """Grouping here as the rest test annotations"""
     return ["a", "b", "c"], {}
diff --git a/tests/test_graph_types.py b/tests/test_graph_types.py
index a152716f0..a289a2660 100644
--- a/tests/test_graph_types.py
+++ b/tests/test_graph_types.py
@@ -216,28 +216,24 @@ def test_json_serializable_dict():
             json.dumps(hamilton_node.as_dict())
 
 
-@pytest.mark.skipif(sys.version_info < (3, 9), reason="requires Python 3.9 or higher")
 def test_remove_docstring(func_a: str, func_a_docstring: str):
     func_a_no_whitespace = func_a.strip()
     stripped = graph_types._remove_docs_and_comments(func_a_docstring)
     assert func_a_no_whitespace == stripped
 
 
-@pytest.mark.skipif(sys.version_info < (3, 9), reason="requires Python 3.9 or higher")
 def test_remove_multiline(func_a: str, func_a_multiline: str):
     func_a_no_whitespace = func_a.strip()
     stripped = graph_types._remove_docs_and_comments(func_a_multiline)
     assert func_a_no_whitespace == stripped
 
 
-@pytest.mark.skipif(sys.version_info < (3, 9), reason="requires Python 3.9 or higher")
 def test_remove_comment(func_a: str, func_a_comment: str):
     func_a_no_whitespace = func_a.strip()
     stripped = graph_types._remove_docs_and_comments(func_a_comment)
     assert func_a_no_whitespace == stripped
 
 
-@pytest.mark.skipif(sys.version_info < (3, 9), reason="requires Python 3.9 or higher")
 @pytest.mark.parametrize("strip", [True, False])
 def test_different_hash_function_body(func_a: str, func_a_body: str, strip: bool):
     """Gives different hash for different function body"""
@@ -246,7 +242,6 @@ def test_different_hash_function_body(func_a: str, func_a_body: str, strip: bool
     assert func_a_hash != func_a_body_hash
 
 
-@pytest.mark.skipif(sys.version_info < (3, 9), reason="requires Python 3.9 or higher")
 @pytest.mark.parametrize("strip", [True, False])
 def test_different_hash_docstring(func_a: str, func_a_docstring: str, strip: bool):
     """Same hash if strip docstring, else different hash"""
@@ -255,7 +250,6 @@ def test_different_hash_docstring(func_a: str, func_a_docstring: str, strip: boo
     assert (func_a_hash == func_a_docstring_hash) is (True if strip else False)
 
 
-@pytest.mark.skipif(sys.version_info < (3, 9), reason="requires Python 3.9 or higher")
 @pytest.mark.parametrize("strip", [True, False])
 def test_different_hash_multiline_docstring(func_a: str, func_a_multiline: str, strip: bool):
     """Same hash if strip multiline docstring, else different hash"""
@@ -264,7 +258,6 @@ def test_different_hash_multiline_docstring(func_a: str, func_a_multiline: str,
     assert (func_a_hash == func_a_multiline_hash) is (True if strip else False)
 
 
-@pytest.mark.skipif(sys.version_info < (3, 9), reason="requires Python 3.9 or higher")
 @pytest.mark.parametrize("strip", [True, False])
 def test_different_hash_comment(func_a: str, func_a_comment: str, strip: bool):
     """Same hash if strip comment, else different hash"""
diff --git a/tests/test_node.py b/tests/test_node.py
index 0411f0557..e77600ea7 100644
--- a/tests/test_node.py
+++ b/tests/test_node.py
@@ -65,7 +65,6 @@ def fn() -> int:
 major, minor, _ = map(int, np_version.split("."))
 
 
-@pytest.mark.skipif(sys.version_info < (3, 9), reason="requires python 3.9 or higher")
 def test_node_handles_annotated():
     from typing import Annotated
 
diff --git a/tests/test_type_utils.py b/tests/test_type_utils.py
index a49e47e1a..5ff1cb130 100644
--- a/tests/test_type_utils.py
+++ b/tests/test_type_utils.py
@@ -16,9 +16,8 @@
 # under the License.
 
 import collections
-import sys
 import typing
-from typing import Any, Dict, List, Union
+from typing import Annotated, Any, Dict, List, Union
 
 import pandas as pd
 import pytest
@@ -26,11 +25,6 @@
 from hamilton import htypes
 from hamilton.htypes import check_instance
 
-if sys.version_info >= (3, 9):
-    from typing import Annotated
-else:
-    from typing_extensions import Annotated
-
 
 class X:
     pass
@@ -308,24 +302,12 @@ def test_check_input_type_match(node_type, input_value):
     assert actual is True
 
 
-# We cannot parameterize this as the parameterization cannot be
-# included if the
-@pytest.mark.skipif(
-    sys.version_info < (3, 9, 0),
-    reason="Type hinting generics in standard collections " "is only supported in 3.9+",
-)
 def test_check_input_types_subscripted_generics_dict_str_Any():
     """Tests check_input_type of SimplePythonDataFrameGraphAdapter"""
     actual = htypes.check_input_type(dict[str, typing.Any], {})
     assert actual is True
 
 
-# We cannot parameterize this as the parameterization cannot be
-# included if the
-@pytest.mark.skipif(
-    sys.version_info < (3, 9, 0),
-    reason="Type hinting generics in standard collections " "is only supported in 3.9+",
-)
 def test_check_input_types_subscripted_generics_list_Any():
     """Tests check_input_type of SimplePythonDataFrameGraphAdapter"""
     actual = htypes.check_input_type(list[typing.Any], [])
@@ -340,10 +322,8 @@ def test_check_instance_with_non_generic_type():
 def test_check_instance_with_generic_list_type():
     assert check_instance([1, 2, 3], List[int])
     assert not check_instance([1, 2, "3"], List[int])
-    if sys.version_info >= (3, 9):
-        # skip 3.8 -- not worth fixing
-        assert check_instance([1, 2, 3], List)
-        assert check_instance([1, 2, "3"], List)
+    assert check_instance([1, 2, 3], List)
+    assert check_instance([1, 2, "3"], List)
 
 
 def test_check_instance_with_list_type():
@@ -354,10 +334,8 @@ def test_check_instance_with_list_type():
 def test_check_instance_with_generic_dict_type():
     assert check_instance({"key1": 1, "key2": 2}, Dict[str, int])
     assert not check_instance({"key1": 1, "key2": "2"}, Dict[str, int])
-    if sys.version_info >= (3, 9):
-        # skip 3.8 -- not worth fixing
-        assert check_instance({"key1": 1, "key2": 2}, Dict)
-        assert check_instance({"key1": 1, "key2": "2"}, Dict)
+    assert check_instance({"key1": 1, "key2": 2}, Dict)
+    assert check_instance({"key1": 1, "key2": "2"}, Dict)
 
 
 def test_check_instance_with_dict_type():
@@ -391,7 +369,6 @@ def test_check_instance_with_union_type():
     assert not check_instance({"key1": 1, "key2": 2}, Union[int, str])
 
 
-@pytest.mark.skipif(sys.version_info < (3, 9), reason="requires python 3.9 or higher")
 def test_check_instance_with_union_type_and_literal():
     from typing import Literal
 
@@ -400,7 +377,6 @@ def test_check_instance_with_union_type_and_literal():
     assert not check_instance("c", Union[Literal["a"], Literal["b"]])
 
 
-@pytest.mark.skipif(sys.version_info < (3, 9), reason="requires python 3.9 or higher")
 def test_non_generic_dict_and_list():
     assert check_instance([1, 2, 3], list[int])
     assert not check_instance([1, 2, "3"], list[int])
