diff --git a/product/ERP5Type/Base.py b/product/ERP5Type/Base.py
index bae63d72c44ddeac4e7a30e2efa3567c85837a31..67e41f18b3f8faeac6f8348effcea382927974bd 100644
--- a/product/ERP5Type/Base.py
+++ b/product/ERP5Type/Base.py
@@ -2924,23 +2924,39 @@ class Base( CopyContainer,
             dynamic_accessor_list.append(subdochelper)
             if getattr(documented_item, property['id'], None) is not None:
               dynamic_property_list.append(subdochelper)
-        if getattr(property_sheet, '_categories', None) is not None:
-          for category in property_sheet._categories:
-            if category in seen_categories:
-              continue
-            seen_categories.append(category)
-            subdochelper = newTempDocumentationHelper(dochelper, category, title=category,
-                      content=pformat(documented_item.getCategoryMembershipList(category)))
-            subdochelper_dynamic_accessor_list = []
-            for accessor_name in generateCategoryAccessorNameList(category):
-              accessor = getattr(item_class, accessor_name, getattr(documented_item, accessor_name, None))
-              # First get it on the class, and if not on the instance, thereby among dynamic accessors.
-              if accessor is not None:
-                subdochelper_dynamic_accessor_list.append(accessorAsDocumentationHelper(accessor))
-            subdochelper_dynamic_accessor_list.sort()
-            subdochelper.setDynamicAccessorList(subdochelper_dynamic_accessor_list)
-            dynamic_accessor_list.append(subdochelper)
-            dynamic_category_list.append(subdochelper)
+        
+        def visitCategory(category):
+          if category in seen_categories:
+            return
+          seen_categories.append(category)
+          subdochelper = newTempDocumentationHelper(dochelper, category, title=category,
+                    content=pformat(documented_item.getCategoryMembershipList(category)))
+          subdochelper_dynamic_accessor_list = []
+          for accessor_name in generateCategoryAccessorNameList(category):
+            accessor = getattr(item_class, accessor_name, getattr(documented_item, accessor_name, None))
+            # First get it on the class, and if not on the instance, thereby among dynamic accessors.
+            if accessor is not None:
+              subdochelper_dynamic_accessor_list.append(accessorAsDocumentationHelper(accessor))
+          subdochelper_dynamic_accessor_list.sort()
+          subdochelper.setDynamicAccessorList(subdochelper_dynamic_accessor_list)
+          dynamic_accessor_list.append(subdochelper)
+          dynamic_category_list.append(subdochelper)
+
+        category_list = getattr(property_sheet, '_categories', [])
+        # some categories are defined by expressions, so we have to do 2
+        # passes, a first one to treat regular category list and collect
+        # categories defined by expression, a second one to treat thoses
+        # new categories from expressions.
+        expression_category_list = []
+        for category in category_list:
+          if isinstance(category, Expression):
+            econtext = createExpressionContext(self)
+            expression_category_list.extend(category(econtext))
+            continue
+          visitCategory(category)
+        
+        for category in expression_category_list:
+          visitCategory(category)
 
 # KEEPME: usefull to track the differences between accessors defined on
 # PortalType and the one detected on the documented item.
diff --git a/product/ERP5Type/tests/testClassTool.py b/product/ERP5Type/tests/testClassTool.py
index 3db94bb158e9de48b243f711fe26d8be4d4fdec7..7a4d6344c0cf49d2dd6853bdb83ad84567ab5ba4 100644
--- a/product/ERP5Type/tests/testClassTool.py
+++ b/product/ERP5Type/tests/testClassTool.py
@@ -128,6 +128,28 @@ class TestClassTool(ERP5TypeTestCase):
     self.assertEquals(0, len(portal.portal_activities.getMessageList()))
    
 
+  def test_DocumentationHelperExpressionCategory(self):
+    # This tests checks that Documentation Helper works with propertysheets
+    # that define their categories using expressions.
+    from Products.ERP5Type.Document.Movement import Movement
+    from Products.CMFCore.Expression import Expression
+    movement = Movement('testing_id').__of__(self.getPortal())
+    # This test relies on the fact that Movement class has categories defined
+    # by an expression. 
+    category_list = []
+    found_one = 0
+    for ps in movement.property_sheets:
+      for category in getattr(ps, '_categories', []):
+        if isinstance(category, Expression):
+          found_one = 1
+      if found_one:
+        break
+    else:
+      self.fail("Movement _categories doesn't include expressions; "
+                "this test is outdated")
+    self.assertNotEquals(None, movement.asDocumentationHelper())
+
+
 import unittest
 def test_suite():
     suite = unittest.TestSuite()