diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5b792cc1fd53e5ccfb54b9d0d84ff248a3eb048d..c3858a9c521128a4182186911c90e60b71ac45b3 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -8,8 +8,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 ## [Unreleased] ##
 
 ### Added ###
+* `ParentList` and `PropertyList` now have a `filter` function that allows to select a subset of
+  the contained elements by ID and/or name.
 
 ### Changed ###
+* `_ParentList` is now called `ParentList`
+* `_Properties` is now called `PropertyList`
+* `ParentList.remove` is now case insensitive when a name is used.
 
 ### Deprecated ###
 
diff --git a/src/linkahead/__init__.py b/src/linkahead/__init__.py
index cd54f8f4e05326579521fbbf226f027d32fa616e..567748e3b3a58fb73b91f652d82ed10f818d6014 100644
--- a/src/linkahead/__init__.py
+++ b/src/linkahead/__init__.py
@@ -42,7 +42,7 @@ from .common.datatype import (BOOLEAN, DATETIME, DOUBLE, FILE, INTEGER, LIST,
                               REFERENCE, TEXT)
 # Import of the basic  API classes:
 from .common.models import (ACL, ALL, FIX, NONE, OBLIGATORY, RECOMMENDED,
-                            SUGGESTED, Container, DropOffBox, Entity, File,
+                            SUGGESTED, Container, DropOffBox, Entity, File, Parent,
                             Info, Message, Permissions, Property, Query,
                             QueryTemplate, Record, RecordType, delete,
                             execute_query, get_global_acl,
diff --git a/src/linkahead/common/models.py b/src/linkahead/common/models.py
index b990e42e67e01d041b13199cd85944522a31ad11..0df706bd6e8bd1be7c7504d9de2590614f9fef27 100644
--- a/src/linkahead/common/models.py
+++ b/src/linkahead/common/models.py
@@ -37,8 +37,10 @@ from __future__ import annotations  # Can be removed with 3.10.
 
 import re
 import sys
+import warnings
 from builtins import str
 from copy import deepcopy
+from enum import Enum
 from datetime import date, datetime
 from functools import cmp_to_key
 from hashlib import sha512
@@ -46,7 +48,6 @@ from os import listdir
 from os.path import isdir
 from random import randint
 from tempfile import NamedTemporaryFile
-
 from typing import TYPE_CHECKING
 from typing import Any, Final, Literal, Optional, TextIO, Union
 
@@ -57,7 +58,6 @@ if TYPE_CHECKING:
     from os import PathLike
     QueryDict = dict[str, Optional[str]]
 
-
 from warnings import warn
 
 from lxml import etree
@@ -156,8 +156,8 @@ class Entity:
         self.datatype: Optional[DATATYPE] = datatype
         self.value = value
         self.messages = Messages()
-        self.properties = _Properties()
-        self.parents = _ParentList()
+        self.properties = PropertyList()
+        self.parents = ParentList()
         self.path: Optional[str] = None
         self.file: Optional[File] = None
         self.unit: Optional[str] = None
@@ -922,7 +922,7 @@ out: bool
     def get_parents(self):
         """Get all parents of this entity.
 
-        @return: _ParentList(list)
+        @return: ParentList(list)
         """
 
         return self.parents
@@ -1022,7 +1022,7 @@ out: list[Entity]
     def get_properties(self):
         """Get all properties of this entity.
 
-        @return: _Properties(list)
+        @return: PropertyList(list)
         """
 
         return self.properties
@@ -2422,11 +2422,14 @@ class File(Record):
             value=value, unit=unit, importance=importance, inheritance=inheritance)
 
 
-class _Properties(list):
-    """FIXME: Add docstring."""
+class PropertyList(list):
+    """A list class for Property objects
+
+    This class provides addional functionality like get/set_importance or get_by_name.
+    """
 
     def __init__(self):
-        list.__init__(self)
+        super().__init__()
         self._importance: dict[Entity, IMPORTANCE] = dict()
         self._inheritance: dict[Entity, INHERITANCE] = dict()
         self._element_by_name: dict[str, Entity] = dict()
@@ -2519,6 +2522,24 @@ class _Properties(list):
 
         return xml2str(xml)
 
+    def filter(self, pid:Union[str, int]=None, name:str =None, prop:Property=None):
+        """
+        Filters all Properties from this PropertyList that match either name or ID.
+
+        You can provide name and or ID via the corresponding arguments or you
+        pass a Property object to this function.
+
+        Parameters
+        ----------
+            pid: Union[str,int], ID of the Properties to be returned
+            name: str, name of the Properties to be returned
+            prop: Property, name of the Properties to be returned
+        Returns
+        -------
+            list, a list with all matching Properties
+        """
+        return _filter_entity_list(self, "Property", pid=pid, name=name, element=prop)
+
     def _get_entity_by_cuid(self, cuid: str):
         '''
         Get the first entity which has the given cuid.
@@ -2576,9 +2597,7 @@ class _Properties(list):
         raise KeyError(str(prop) + " not found.")
 
 
-class _ParentList(list):
-    # TODO unclear why this class is private. Isn't it use full for users?
-
+class ParentList(list):
     def _get_entity_by_cuid(self, cuid):
         '''
         Get the first entity which has the given cuid.
@@ -2593,8 +2612,8 @@ class _ParentList(list):
                     return e
         raise KeyError("No entity with that cuid in this container.")
 
-    def __init__(self):
-        list.__init__(self)
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args, **kwargs)
         self._element_by_name = dict()
         self._element_by_id = dict()
 
@@ -2607,15 +2626,9 @@ class _ParentList(list):
         if isinstance(parent, list):
             for p in parent:
                 self.append(p)
-
             return
 
         if isinstance(parent, Entity):
-            if parent.id:
-                self._element_by_id[str(parent.id)] = parent
-
-            if parent.name:
-                self._element_by_name[parent.name] = parent
             list.append(self, parent)
         else:
             raise TypeError("Argument was not an Entity")
@@ -2657,7 +2670,34 @@ class _ParentList(list):
 
         return xml2str(xml)
 
+    def filter(self, pid:Union[str, int]=None, name:str =None, parent:Parent=None):
+        """
+        Filters all Parents from this ParentList that match either name or ID.
+
+        You can provide name and or ID via the corresponding arguments or you
+        pass a Parent object to this function.
+
+        Returns
+        -------
+            a list with all matching Parents
+        """
+        return _filter_entity_list(self, "Parent", pid=pid, name=name, element=parent)
+
     def remove(self, parent: Union[Entity, int, str]):
+        """
+        Remove first occurrence of parent.
+
+        Parameters
+        ----------
+        parent: Union[Entity, int, str], the parent to be removed identified via ID or name. If a
+        Parent object is provided the ID and then the name is used to identify the parent to be
+        removed.
+
+        Returns
+        -------
+        None
+        """
+
         if isinstance(parent, Entity):
             if parent in self:
                 list.remove(self, parent)
@@ -2675,11 +2715,11 @@ class _ParentList(list):
                     # by name
 
                     for e in self:
-                        if e.name is not None and e.name == parent.name:
+                        if e.name is not None and e.name.lower() == parent.name.lower():
                             list.remove(self, e)
 
                             return
-        elif hasattr(parent, "encode"):
+        elif isinstance(parent, str):
             # by name
 
             for e in self:
@@ -2698,6 +2738,19 @@ class _ParentList(list):
         raise KeyError(str(parent) + " not found.")
 
 
+class _Properties(PropertyList):
+    def __init__(self, *args, **kwargs):
+        warnings.warn(DeprecationWarning("This class is depricated. Please use PropertyList."))
+        super().__init__(*args, **kwargs)
+
+
+class _ParentList(ParentList):
+    def __init__(self, *args, **kwargs):
+        warnings.warn(DeprecationWarning("This class is depricated. Please use ParentList "
+                                         "(without underscore)."))
+        super().__init__(*args, **kwargs)
+
+
 class Messages(list):
     """This specialization of list stores error, warning, info, and other
     messages. The mentioned three messages types play a special role.
@@ -5392,3 +5445,30 @@ def delete(ids: Union[list[int], range], raise_exception_on_error: bool = True):
         c.append(Entity(id=ids))
 
     return c.delete(raise_exception_on_error=raise_exception_on_error)
+
+def _filter_entity_list(listobject, element_type, pid:Union[str, int]=None, name:str =None, element:Any=None):
+        """
+        Filterss all elements from the given list that match either name or ID.
+
+        You can provide name and or ID via the corresponding arguments or you
+        pass an  object to this function that has id and/or name.
+
+        Returns
+        -------
+            a list with all matching elements
+        """
+        if element is not None:
+            if pid is not None or name is not None:
+                raise ValueError(f"Please provide either a {element_type} or one of "
+                                 "pid or name")
+            pid = element.id
+            name = element.name
+
+        candidates = []
+        if name is not None:
+            candidates.extend(
+                [p for p in listobject if p.name is not None and p.name.lower() == name.lower()])
+        if pid is not None:
+            candidates.extend(
+                [p for p in listobject if p.id == pid])
+        return candidates
diff --git a/unittests/test_entity.py b/unittests/test_entity.py
index d059f7e29a50161e85b2d708c05cd9e0c5254f65..1b3e9d24e3eb8c79d05bd372e18ea27e3f55ddb6 100644
--- a/unittests/test_entity.py
+++ b/unittests/test_entity.py
@@ -22,15 +22,17 @@
 # ** end header
 #
 """Tests for the Entity class."""
+import os
 # pylint: disable=missing-docstring
 import unittest
-from lxml import etree
+from pytest import raises
 
-import os
-from linkahead import (INTEGER, Entity, Property, Record, RecordType,
+import linkahead
+from linkahead import (INTEGER, Entity, Property, Record, RecordType, Parent,
                        configure_connection)
 from linkahead.common.models import SPECIAL_ATTRIBUTES
 from linkahead.connection.mockup import MockUpServerConnection
+from lxml import etree
 
 UNITTESTDIR = os.path.dirname(os.path.abspath(__file__))
 
@@ -104,3 +106,75 @@ class TestEntity(unittest.TestCase):
         # test whether the __role property of this object has explicitely been
         # set.
         self.assertEqual(getattr(entity, "_Entity__role"), "Record")
+
+
+def test_parent_list():
+    p1 = RecordType(name="A")
+    pl = linkahead.common.models.ParentList([p1])
+    assert p1 in pl
+    assert pl.index(p1) == 0
+    assert RecordType(name="A") not in pl
+    assert RecordType(id=101) not in pl
+    p2 = RecordType(id=101)
+    pl.append(p2)
+    assert p2 in pl
+    assert len(pl) == 2
+    assert p1 in pl.filter(name="A")
+    assert p2 in pl.filter(pid=101)
+    assert p2 in pl.filter(pid=101, name="A")
+    assert p1 in pl.filter(pid=101, name="A")
+    assert p1 in pl.filter(parent=Parent(id=101, name="A"))
+    assert p2 in pl.filter(parent=Parent(id=101, name="A"))
+    p3 = RecordType(id=103, name='B')
+    pl.append(p3)
+    assert len(pl) == 3
+    assert p3 in pl.filter(name="B")
+    assert p3 in pl.filter(pid=103)
+
+    # test removal
+    # remove by id only, even though element in parent list has name and id
+    pl.remove(RecordType(id=103))
+    assert len(pl) == 2
+    assert p3 not in pl
+    assert p2 in pl
+    assert p1 in pl
+    # Same for removal by name
+    pl.append(p3)
+    assert len(pl) == 3
+    pl.remove(RecordType(name='B'))
+    assert len(pl) == 2
+    assert p3 not in pl
+    # And an error if no suitable element can be found
+    with raises(KeyError) as ve:
+        pl.remove(RecordType(id=105, name='B'))
+    assert "not found" in str(ve.value)
+    assert len(pl) == 2
+
+    # TODO also check pl1 == pl2
+
+
+
+
+def test_property_list():
+    # TODO: Resolve parent-list TODOs, then transfer to here.
+    # TODO: What other considerations have to be done with properties?
+    p1 = Property(name="A")
+    pl = linkahead.common.models.PropertyList()
+    pl.append(p1)
+    assert p1 in pl
+    assert Property(id=101) not in pl
+    p2 = Property(id=101)
+    pl.append(p2)
+    assert p1 in pl
+    assert p2 in pl
+    p3 = Property(id=103, name='B')
+    pl.append(p3)
+
+    assert p1 in pl.filter(name="A")
+    assert p2 in pl.filter(pid=101)
+    assert p2 in pl.filter(pid=101, name="A")
+    assert p1 in pl.filter(pid=101, name="A")
+    assert p1 in pl.filter(prop=Property(id=101, name="A"))
+    assert p2 in pl.filter(prop=Property(id=101, name="A"))
+    assert p3 in pl.filter(name="B")
+    assert p3 in pl.filter(pid=103)