diff --git a/CHANGELOG.md b/CHANGELOG.md
index cd4f2ab2863999774af6a751f378da00b81a83e7..d11fec28d0a6bf454ce6a218b0c833476bf9d3a0 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -17,6 +17,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 
 ### Fixed ###
 
+* [#64](https://gitlab.com/caosdb/caosdb-pylib/-/issues/64) Use `Dict[]` and
+  `List[]` from `typing` for type hinting instead of `dict[]` and `list[]` for
+  compatibility with Python<3.9.
+
 ### Security ###
 
 ### Documentation ###
diff --git a/src/caosdb/apiutils.py b/src/caosdb/apiutils.py
index a376068c372c1b6f460c7927467b8da8df328545..4c8393111bcbb4f9f91e309b81bebdcac55ba626 100644
--- a/src/caosdb/apiutils.py
+++ b/src/caosdb/apiutils.py
@@ -33,7 +33,7 @@ import warnings
 from collections.abc import Iterable
 from subprocess import call
 
-from typing import Optional, Any
+from typing import Optional, Any, Dict, List
 
 from caosdb.common.datatype import (BOOLEAN, DATETIME, DOUBLE, FILE, INTEGER,
                                     REFERENCE, TEXT, is_reference)
@@ -205,8 +205,8 @@ def compare_entities(old_entity: Entity, new_entity: Entity):
         In case of changed information the value listed under the respective key shows the
         value that is stored in the respective entity.
     """
-    olddiff: dict[str, Any] = {"properties": {}, "parents": []}
-    newdiff: dict[str, Any] = {"properties": {}, "parents": []}
+    olddiff: Dict[str, Any] = {"properties": {}, "parents": []}
+    newdiff: Dict[str, Any] = {"properties": {}, "parents": []}
 
     if old_entity is new_entity:
         return (olddiff, newdiff)
@@ -467,7 +467,7 @@ def resolve_reference(prop: Property):
             prop.value = retrieve_entity_with_id(prop.value)
 
 
-def create_flat_list(ent_list: list[Entity], flat: list[Entity]):
+def create_flat_list(ent_list: List[Entity], flat: List[Entity]):
     """
     Recursively adds all properties contained in entities from ent_list to
     the output list flat. Each element will only be added once to the list.
@@ -483,8 +483,10 @@ def create_flat_list(ent_list: list[Entity], flat: list[Entity]):
                     if isinstance(el, Entity):
                         if el not in flat:
                             flat.append(el)
-                        create_flat_list([el], flat)  # TODO: move inside if block?
+                        # TODO: move inside if block?
+                        create_flat_list([el], flat)
             elif isinstance(p.value, Entity):
                 if p.value not in flat:
                     flat.append(p.value)
-                create_flat_list([p.value], flat)  # TODO: move inside if block?
+                # TODO: move inside if block?
+                create_flat_list([p.value], flat)
diff --git a/src/caosdb/high_level_api.py b/src/caosdb/high_level_api.py
index 0c936112993ccdbb5afdd91f3286880a16bdf431..427a095a4bafc0c372b0169298f2980dbd902c49 100644
--- a/src/caosdb/high_level_api.py
+++ b/src/caosdb/high_level_api.py
@@ -561,7 +561,7 @@ class CaosDBPythonEntity(object):
         return propval
 
     def resolve_references(self, deep: bool, references: db.Container,
-                           visited: dict[Union[str, int],
+                           visited: Dict[Union[str, int],
                                          "CaosDBPythonEntity"] = None):
         """
         Resolve this entity's references. This affects unresolved properties as well
@@ -692,7 +692,7 @@ class CaosDBPythonEntity(object):
         if self in visited:
             return visited[self]
 
-        metadata: dict[str, Any] = dict()
+        metadata: Dict[str, Any] = dict()
         properties = dict()
         parents = list()
 
diff --git a/src/caosdb/utils/plantuml.py b/src/caosdb/utils/plantuml.py
index 16bd81d9507b9ecd11870e18b1020d9f47b8f047..6252a48983c62e7a2f33113422205209d616b5b6 100644
--- a/src/caosdb/utils/plantuml.py
+++ b/src/caosdb/utils/plantuml.py
@@ -39,7 +39,7 @@ import shutil
 import caosdb as db
 from caosdb.common.datatype import is_reference, get_referenced_recordtype
 
-from typing import Optional
+from typing import List, Optional
 
 import tempfile
 
@@ -341,9 +341,9 @@ def retrieve_substructure(start_record_types, depth, result_id_set=None, result_
     return None
 
 
-def to_graphics(recordtypes: list[db.Entity], filename: str,
+def to_graphics(recordtypes: List[db.Entity], filename: str,
                 output_dirname: Optional[str] = None,
-                formats: list[str] = ["tsvg"],
+                formats: List[str] = ["tsvg"],
                 silent: bool = True,
                 add_properties: bool = True,
                 add_recordtypes: bool = True,
@@ -367,7 +367,7 @@ def to_graphics(recordtypes: list[db.Entity], filename: str,
                      the destination directory for the resulting images as defined by the "-o"
                      option by plantuml
                      default is to use current working dir
-    formats : list[str]
+    formats : List[str]
               list of target formats as defined by the -t"..." options by plantuml, e.g. "tsvg"
     silent : bool
              Don't output messages.