diff --git a/src/linkahead/common/models.py b/src/linkahead/common/models.py
index 0df706bd6e8bd1be7c7504d9de2590614f9fef27..fe15b1a7f843af110471a624802b3a93efe8a035 100644
--- a/src/linkahead/common/models.py
+++ b/src/linkahead/common/models.py
@@ -2522,23 +2522,50 @@ class PropertyList(list):
 
         return xml2str(xml)
 
-    def filter(self, pid:Union[str, int]=None, name:str =None, prop:Property=None):
+    def filter(self, prop:Property = None, pid:Union[str, int] = None,
+               name:str = None, check_equality: bool = False,
+               check_wrap: bool = True) -> list:
         """
-        Filters all Properties from this PropertyList that match either name or ID.
+        Return all Properties from the given PropertyList that match the
+        selection criteria.
 
-        You can provide name and or ID via the corresponding arguments or you
-        pass a Property object to this function.
+        You can provide name or ID and all matching elements will be returned.
+        If both name and ID are given, elements matching either criterion will
+        be returned.
+
+        If a Property is given, neither name nor ID may be set. In this case,
+        only elements matching both name and ID of the Property are returned.
+
+        Also checks the original Properties wrapped within the elements of
+        PropertyList and will return the original Property if both wrapper and
+        original match.
+
+        Params
+        ------
+            listobject        : Iterable(Property)
+                                List to be filtered
+            prop              : Property
+                                Property to match name and ID with. Cannot be
+                                set simultaneously with ID or name.
+            pid               : str, int
+                                Property ID to match
+            name              : str
+                                Property name to match
+            check_equality    : bool, default: False
+                                If set to True, potential matches will be checked
+                                using the equality operator instead of ID and name.
+                                Will be ignored if the prop parameter is not set.
+            check_wrap        : bool, default: True
+                                If set to False, only the wrapper elements
+                                contained in the given PropertyList will be
+                                checked, not the original Properties they wrap.
 
-        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
+            list with all matching Properties
         """
-        return _filter_entity_list(self, "Property", pid=pid, name=name, element=prop)
+        return _filter_entity_list(self, pid=pid, name=name, entity=prop,
+                                   check_equality=check_equality, check_wrap=check_wrap)
 
     def _get_entity_by_cuid(self, cuid: str):
         '''
@@ -2670,18 +2697,50 @@ class ParentList(list):
 
         return xml2str(xml)
 
-    def filter(self, pid:Union[str, int]=None, name:str =None, parent:Parent=None):
+    def filter(self, parent:Parent = None, pid:Union[str, int] = None,
+               name:str = None, check_equality: bool = False,
+               check_wrap: bool = True) -> list:
         """
-        Filters all Parents from this ParentList that match either name or ID.
+        Return all Parents from the given ParentList that match the selection
+        criteria.
 
-        You can provide name and or ID via the corresponding arguments or you
-        pass a Parent object to this function.
+        You can provide name or ID and all matching elements will be returned.
+        If both name and ID are given, elements matching either criterion will
+        be returned.
+
+        If a Parent is given, neither name nor ID may be set. In this case,
+        only elements matching both name and ID of the Parent are returned.
+
+        Also checks the original Parents wrapped within the elements of
+        ParentList, will return the original Parent if both wrapper and
+        original match.
+
+        Params
+        ------
+            listobject        : Iterable(Parent)
+                                List to be filtered
+            parent            : Parent
+                                Parent to match name and ID with. Cannot be set
+            pid               : str, int
+                                Parent ID to match
+            name              : str
+                                Parent name to match
+                                simultaneously with ID or name.
+            check_equality    : bool, default: False
+                                If set to True, potential matches will be checked
+                                using the equality operator instead of ID and name.
+                                Will be ignored if the entity parameter is not set.
+            check_wrap        : bool, default: True
+                                If set to False, only the wrapper elements
+                                contained in the given ParentList will be
+                                checked, not the original Parents they wrap.
 
         Returns
         -------
-            a list with all matching Parents
+            list with all matching Parents
         """
-        return _filter_entity_list(self, "Parent", pid=pid, name=name, element=parent)
+        return _filter_entity_list(self, pid=pid, name=name, entity=parent,
+                                   check_equality=check_equality, check_wrap=check_wrap)
 
     def remove(self, parent: Union[Entity, int, str]):
         """
@@ -5446,29 +5505,108 @@ def delete(ids: Union[list[int], range], raise_exception_on_error: bool = True):
 
     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.
+def _filter_entity_list(listobject, entity:Entity = None, pid:Union[str, int] = None,
+                        name:str = None, check_equality:bool = False,
+                        check_wrap:bool = True) -> list:
+    """
+    Return all elements from the given list that match the selection criteria.
+
+    You can provide name or ID and all matching elements will be returned.
+    If both name and ID are given, elements matching either criterion will be
+    returned. 
+    
+    If an Entity is given, neither name nor ID may be set. In this case, only
+    elements matching both name and ID of the Entity are returned.
+
+    In case the elements contained in the given list are wrapped, the function
+    in its default configuration checks both the wrapped and wrapper Entity
+    against the match criteria, and will return the wrapped Entity if both
+    match. Note that this is currently not iterative, meaning that only the
+    first layer of wrapped entity is considered.
+
+    Params
+    ------
+        listobject        : Iterable(Entity)
+                            List to be filtered
+        entity            : Entity
+                            Entity to match name and ID for. Cannot be set
+                            simultaneously with ID or name.
+        pid               : str, int
+                            Entity ID to match
+        name              : str
+                            Entity name to match
+        check_equality    : bool, default: False
+                            If set to True, potential matches will be checked
+                            using the equality operator instead of ID and name.
+                            Will be ignored if the entity parameter is not set.
+        check_wrap        : bool, default: True
+                            If set to False, only the wrapper elements
+                            contained in the given list will be checked, not
+                            the original Entities they wrap.
+
+    Returns
+    -------
+        list with all matching Entities
+    """
+    # Check correct input params and setup
+    match_entity = False
+    if entity is not None:
+        if pid is not None or name is not None:
+            raise ValueError("Please provide either Entity, pid or name.")
+        pid = entity.id
+        name = entity.name
+        match_entity = True
+    else:
+        check_equality = False
+
+    # Iterate through list and match based on given criteria
+    matches = []
+    potentials = list(zip(listobject.copy(), [False]*len(listobject)))
+    for candidate, wrapped_is_checked in potentials:
+        name_match, pid_match, original_candidate = False, False, None
+
+        # Parents/Properties may be wrapped - if indicated, try to match original
+        # Note: if we want to check all wrapped Entities, this should be switched.
+        #       First check the wrap, then append wrapped. In this case we also
+        #       don't need wrapped_checked, but preferentially append the wrapper.
+        if check_wrap and not wrapped_is_checked:
+            try:
+                if candidate._wrapped_entity is not None:
+                    original_candidate = candidate
+                    candidate = candidate._wrapped_entity
+            except:
+                pass
 
-        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
+        # If indicated, only consider equality
+        if check_equality:
+            if candidate == entity:
+                matches.append(candidate)
+            elif original_candidate is not None:
+                potentials.append((original_candidate, True))
+            continue
+        # Otherwise, check whether name/pid match
+        if pid is not None and candidate.id == pid:
+            pid_match = True
+        elif match_entity and candidate.id == pid:
+            # If we are matching the entity, both being Null is also satisfactory
+            pid_match = True
+        if (name is not None and candidate.name is not None
+                and candidate.name.lower() == name.lower()):
+            name_match = True
+        elif match_entity and candidate.name == name:
+            # If we are matching the entity, both being Null is also satisfactory
+            name_match = True
+
+        # If the criteria are satisfied, append the match. Otherwise, check
+        # the wrapper if applicable
+        # ToDo: Check whether it would make sense to also check RecordType
+        #       for match_entity
+        if name_match and pid_match:
+            matches.append(candidate)
+        elif not match_entity and (name_match or pid_match):
+            matches.append(candidate)
+        else:
+            if original_candidate is not None:
+                potentials.append((original_candidate, True))
+    return matches
diff --git a/unittests/test_entity.py b/unittests/test_entity.py
index 1b3e9d24e3eb8c79d05bd372e18ea27e3f55ddb6..cff6d8dc01a04688232f92ba5e9064755b5bff1b 100644
--- a/unittests/test_entity.py
+++ b/unittests/test_entity.py
@@ -119,17 +119,9 @@ def test_parent_list():
     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
@@ -153,8 +145,6 @@ def test_parent_list():
     # 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?
@@ -170,11 +160,81 @@ def test_property_list():
     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)
+
+def test_filter():
+    rt1 = RecordType(id=100)
+    rt2 = RecordType(id=101, name="RT")
+    rt3 = RecordType()
+    p1 = Property(id=100)
+    p2 = Property(id=100)
+    p3 = Property(id=101, name="RT")
+    p4 = Property(id=102, name="P")
+    p5 = Property(id=103, name="P")
+    p6 = Property()
+    r1 = Record(id=100)
+    r2 = Record(id=100)
+    r3 = Record(id=101, name="RT")
+    r4 = Record(id=101, name="R")
+    r5 = Record(id=104, name="R")
+    r6 = Record(id=105, name="R")
+    test_ents = [rt1, rt2, rt3, p1, p2, p3, p4, p5, p6, r1, r2, r3, r4, r5, r6]
+
+    ###   Setup
+    t1 = Property()
+    t1_props, t1_pars = t1.properties, t1.parents
+    t2 = Record()
+    t2_props, t2_pars = t2.properties, t2.parents
+    t3 = RecordType()
+    t3_props, t3_pars = t3.properties, t3.parents
+    test_colls = [t1_props, t1_pars, t2_props, t2_pars, t3_props, t3_pars]
+    for coll in test_colls:
+        for ent in test_ents:
+            assert ent not in coll
+            assert ent not in coll.filter(ent)
+
+    ###   Checks with each type
+    for t ,t_props, t_pars in [(t1, t1_props, t1_pars), (t2, t2_props, t2_pars),
+                               (t3, t3_props, t3_pars)]:
+        ##  Properties
+        # Basic Checks
+        t.add_property(p1)
+        t.add_property(p3)
+        assert p1 in t_props.filter(pid=100)
+        assert p1 in t_props.filter(p1, check_equality=True)
+        assert p1 not in t_props.filter(pid=101, name="RT")
+        for entity in [rt1, p2, r1, r2]:
+            assert entity not in t_props.filter(pid=100)
+            assert p1 in t_props.filter(entity)
+            assert p1 not in t_props.filter(entity, check_equality=True)
+        # Check that direct addition (not wrapped) works
+        t_props.append(p2)
+        assert p2 in t_props.filter(pid=100)
+        assert p2 in t_props.filter(p2, check_equality=True)
+        assert p2 not in t_props.filter(pid=101, name="RT")
+        for entity in [rt1, r1, r2]:
+            assert entity not in t_props.filter(pid=100)
+            assert p2 in t_props.filter(entity)
+            assert p2 not in t_props.filter(entity, check_equality=True)
+
+        ##  Parents
+        # Filtering with both name and id
+        t.add_parent(r3)
+        t.add_parent(r5)
+        assert r3 in t_pars.filter(pid=101)
+        assert r5 not in t_pars.filter(pid=101)
+        assert r3 not in t_pars.filter(name="R")
+        assert r5 in t_pars.filter(name="R")
+        assert r3 in t_pars.filter(pid=101, name="R")
+        assert r5 in t_pars.filter(pid=101, name="R")
+        assert r3 in t_pars.filter(pid=104, name="RT")
+        assert r5 in t_pars.filter(pid=104, name="RT")
+        assert r3 not in t_pars.filter(pid=105, name="T")
+        assert r5 not in t_pars.filter(pid=105, name="T")
+        # Works also without id / name and with duplicate parents
+        for ent in test_ents:
+            t.add_parent(ent)
+        for ent in test_ents:
+            assert ent in t_pars.filter(ent)
+            assert ent in t_pars.filter(ent, check_equality=True)
+        # ToDo: Check whether duplicates are wanted and write tests for the
+        #       desirable outcome