diff --git a/nodes.py b/nodes.py
index 31cf32b3757a001f42ccf12f194e37351f81dce0_bm9kZXMucHk=..dabf37c4ca94dac430cc34cc0551b0c794028b1d_bm9kZXMucHk= 100644
--- a/nodes.py
+++ b/nodes.py
@@ -84,8 +84,8 @@
         except AttributeError:
             return None
 
-    def get_description(self):
-        return self.get_type()
+    def get_description(self, mainindex, tr):
+        return tr(self.get_type())
 
 
 # rql st edition utilities ####################################################
@@ -559,8 +559,8 @@
                 return 'Float'
             raise CoercionError(key)
 
-    def get_description(self):
+    def get_description(self, mainindex, tr):
         """if there is a variable in the math expr used as rhs of a relation,
         return the name of this relation, else return the type of the math
         expression
         """
@@ -563,13 +563,14 @@
         """if there is a variable in the math expr used as rhs of a relation,
         return the name of this relation, else return the type of the math
         expression
         """
-        schema = self.root.schema
-        for vref in self.iget_nodes(VariableRef):
-            rtype = vref.get_description()
-            if schema.has_relation(rtype):
-                return rtype
-        return self.get_type()
+        try:
+            return tr(self.get_type())
+        except CoercionError:
+            for vref in self.iget_nodes(VariableRef):
+                type = vref.get_description(mainindex, tr)
+                if type is not None :
+                    return type
 
 
 class Function(HSMixin, Node):
@@ -613,8 +614,8 @@
                 pass
         return rtype or 'Any'
 
-    def get_description(self):
-        return self.descr().st_description(self)
+    def get_description(self, mainindex, tr):
+        return self.descr().st_description(self, mainindex, tr)
 
     def descr(self):
         """return the type of object returned by this function if known"""
@@ -739,8 +740,8 @@
     def get_type(self, solution=None, kwargs=None):
         return self.variable.get_type(solution, kwargs)
 
-    def get_description(self):
-        return self.variable.get_description()
+    def get_description(self, mainindex, tr):
+        return self.variable.get_description(mainindex, tr)
 
 
 class SortTerm(Node):
@@ -856,7 +857,7 @@
                     pass
         return 'Any'
 
-    def get_description(self):
+    def get_description(self, mainindex, tr, none_allowed=False):
         """return :
         * the name of a relation where this variable is used as lhs,
         * the entity type of this object if specified by a 'is' relation,
@@ -864,6 +865,9 @@
 
         give priority to relation name
         """
-        etype = 'Any'
-        rtype = None
+        if mainindex is not None:
+            if mainindex in self.stinfo['selected']:
+                return ', '.join(sorted(
+                    tr(etype) for etype in self.stinfo['possibletypes']))
+        rtype = frtype = None
         schema = self.schema
@@ -869,13 +873,6 @@
         schema = self.schema
-        for rel in chain(self.stinfo['typerels'], self.stinfo['relations']):
-            if rel.is_types_restriction():
-                try:
-                    etype = str(rel.children[1].children[0].value)
-                except AttributeError:
-                    # "IN" Function node
-                    pass
-                continue
+        for rel in self.stinfo['relations']:
             if schema is not None:
                 rschema = schema.rschema(rel.r_type)
                 if rschema.is_final():
                     if self.name == rel.children[0].name:
@@ -878,10 +875,9 @@
             if schema is not None:
                 rschema = schema.rschema(rel.r_type)
                 if rschema.is_final():
                     if self.name == rel.children[0].name:
-                        continue # ignore
-                    rtype = rel.r_type
-                    break
-            else:
-                print 'NO SCHEMA', repr(self), repr(self.stmt.root)
+                        # ignore final relation where this variable is used as subject
+                        continue
+                    # final relation where this variable is used as object
+                    frtype = rel.r_type
             rtype = rel.r_type
@@ -887,9 +883,26 @@
             rtype = rel.r_type
-            # use getattr since variable may have been rewritten
-            if not self.name != getattr(rel.children[0], 'name', None):
-                # priority to relation where variable is on the rhs
-                break
-        return rtype or etype
+            lhs, rhs = rel.get_variable_parts()
+            # use getattr, may not be a variable ref (rewritten, constant...)
+            lhsvar = getattr(lhs, 'variable', None)
+            rhsvar = getattr(rhs, 'variable', None)
+            if mainindex is not None:
+                # relation to the main variable, stop searching
+                if mainindex in lhsvar.stinfo['selected']:
+                    return tr(rtype)
+                if mainindex in rhsvar.stinfo['selected']:
+                    if schema is not None and rschema.symetric:
+                        return tr(rtype)
+                    return tr(rtype + '_object')
+            if rhsvar is self:
+                rtype += '_object'
+        if frtype is not None:
+            return tr(frtype)
+        if mainindex is None and rtype is not None:
+            return tr(rtype)
+        if none_allowed:
+            return None
+        return ', '.join(sorted(
+            tr(etype) for etype in self.stinfo['possibletypes']))
 
     def selected_index(self):
         """return the index of this variable in the selection if it's selected,
@@ -939,5 +952,5 @@
                     return vtype
         return vtype
 
-    def get_description(self):
+    def get_description(self, mainindex, tr):
         """return entity type of this object, 'Any' if not found"""
@@ -943,4 +956,6 @@
         """return entity type of this object, 'Any' if not found"""
-        vtype = super(ColumnAlias, self).get_description()
-        if vtype == 'Any':
+        vtype = super(ColumnAlias, self).get_description(mainindex, tr,
+                                                         none_allowed=True)
+        if vtype is None:
+            vtypes = set()
             for select in self.query.children:
@@ -946,7 +961,9 @@
             for select in self.query.children:
-                vtype = select.selection[self.colnum].get_description()
-                if vtype != 'Any':
-                    return vtype
+                vtype = select.selection[self.colnum].get_description(mainindex, tr)
+                if vtype is not None:
+                    vtypes.add(vtype)
+            if vtypes:
+                return ', '.join(sorted(tr(vtype) for vtype in vtypes))
         return vtype
 
     # Variable compatibility
diff --git a/stmts.py b/stmts.py
index 31cf32b3757a001f42ccf12f194e37351f81dce0_c3RtdHMucHk=..dabf37c4ca94dac430cc34cc0551b0c794028b1d_c3RtdHMucHk= 100644
--- a/stmts.py
+++ b/stmts.py
@@ -225,8 +225,18 @@
             return self
         return self.parent.root
 
-    def get_description(self):
-        return [c.get_description() for c in self.children]
+    def get_description(self, mainindex=None, tr=None):
+        """
+        `mainindex`:
+          selection index to consider as main column, useful to get smarter
+          results
+        `tr`:
+          optional translation function taking a string as argument and
+          returning a string
+        """
+        if tr is None:
+            tr = lambda x: x
+        return [c.get_description(mainindex, tr) for c in self.children]
 
     # repr / as_string / copy #################################################
 
@@ -369,5 +379,5 @@
         """return the root node of the tree"""
         return self.parent
 
-    def get_description(self):
+    def get_description(self, mainindex, tr):
         """return the list of types or relations (if not found) associated to
@@ -373,6 +383,8 @@
         """return the list of types or relations (if not found) associated to
-        selected variables
+        selected variables.
+        mainindex is an optional selection index which should be considered has
+        'pivot' entity.
         """
         descr = []
         for term in self.selection:
             try:
@@ -375,6 +387,6 @@
         """
         descr = []
         for term in self.selection:
             try:
-                descr.append(term.get_description())
+                descr.append(term.get_description(mainindex, tr) or tr('Any'))
             except CoercionError:
@@ -380,5 +392,5 @@
             except CoercionError:
-                descr.append('Any')
+                descr.append(tr('Any'))
         return descr
 
     @property
diff --git a/test/unittest_nodes.py b/test/unittest_nodes.py
index 31cf32b3757a001f42ccf12f194e37351f81dce0_dGVzdC91bml0dGVzdF9ub2Rlcy5weQ==..dabf37c4ca94dac430cc34cc0551b0c794028b1d_dGVzdC91bml0dGVzdF9ub2Rlcy5weQ== 100644
--- a/test/unittest_nodes.py
+++ b/test/unittest_nodes.py
@@ -8,8 +8,14 @@
 schema = DummySchema()
 from rql.stcheck import RQLSTAnnotator
 annotator = RQLSTAnnotator(schema, {})
+helper = RQLHelper(schema, None, {'eid': 'uid'})
+
+def sparse(rql):
+    tree = helper.parse(rql)
+    helper.compute_solutions(tree)
+    return tree
 
 class EtypeFromPyobjTC(TestCase):
     def test_bool(self):
         self.assertEquals(nodes.etype_from_pyobj(True), 'Boolean')
         self.assertEquals(nodes.etype_from_pyobj(False), 'Boolean')
@@ -11,9 +17,9 @@
 
 class EtypeFromPyobjTC(TestCase):
     def test_bool(self):
         self.assertEquals(nodes.etype_from_pyobj(True), 'Boolean')
         self.assertEquals(nodes.etype_from_pyobj(False), 'Boolean')
-        
+
     def test_int(self):
         self.assertEquals(nodes.etype_from_pyobj(0), 'Int')
         self.assertEquals(nodes.etype_from_pyobj(1L), 'Int')
@@ -452,7 +458,7 @@
     # sub-queries tests #######################################################
     
     def test_subq_colalias_compat(self):
-        tree = parse('Any X ORDERBY N WHERE X creation_date <NOW WITH X,N BEING ('
+        tree = sparse('Any X ORDERBY N WHERE X creation_date <NOW WITH X,N BEING ('
                      '(Any X,N WHERE X firstname N) UNION (Any X,N WHERE X name N, X is Company))')
         select = tree.children[0]
         select.save_state()
@@ -463,8 +469,8 @@
         self.assertEquals(len(X.references()), 3)
         self.assertEquals(len(N.references()), 2)
         tree.schema = schema
-        annotator.annotate(tree)
+        #annotator.annotate(tree)
         # XXX how to choose
         self.assertEquals(X.get_type(), 'Company')
         self.assertEquals(X.get_type({'X': 'Personne'}), 'Personne')
         #self.assertEquals(N.get_type(), 'String')
@@ -467,9 +473,9 @@
         # XXX how to choose
         self.assertEquals(X.get_type(), 'Company')
         self.assertEquals(X.get_type({'X': 'Personne'}), 'Personne')
         #self.assertEquals(N.get_type(), 'String')
-        self.assertEquals(X.get_description(), 'Company')
-        self.assertEquals(N.get_description(), 'firstname') # XXX how to choose 
+        self.assertEquals(X.get_description(0, lambda x:x), 'Company, Person, Student')
+        self.assertEquals(N.get_description(0, lambda x:x), 'firstname, name')
         self.assertEquals(X.selected_index(), 0)
         self.assertEquals(N.selected_index(), None)
         self.assertEquals(X.main_relation(), None)
@@ -477,5 +483,5 @@
     # non regression tests ####################################################
     
     def test_get_description_and_get_type(self):
-        tree = parse("Any N,COUNT(X),NOW-D GROUPBY N WHERE X name N, X creation_date D;")
+        tree = sparse("Any N,COUNT(X),NOW-D GROUPBY N WHERE X name N, X creation_date D;")
         tree.schema = schema
@@ -481,6 +487,5 @@
         tree.schema = schema
-        annotator.annotate(tree)
-        self.assertEqual(tree.get_description(), [['name', 'COUNT(Any)', 'creation_date']])
+        self.assertEqual(tree.get_description(), [['name', 'COUNT(Company, Person, Student)', 'creation_date']])
         select = tree.children[0]
         self.assertEqual(select.selection[0].get_type(), 'Any')
         self.assertEqual(select.selection[1].get_type(), 'Int')
@@ -488,8 +493,6 @@
         self.assertEqual(select.selection[2].get_type({'D': 'Datetime'}), 'Interval')
 
     def test_get_description_simplified(self):
-        helper = RQLHelper(DummySchema(), None, {'eid': 'uid'})
-        tree = helper.parse('Any X,R,D WHERE X eid 2, X work_for R, R creation_date D')        
-        select = tree.children[0]
-        self.assertEqual(tree.get_description(), [['work_for', 'work_for', 'creation_date']])
+        tree = sparse('Any X,R,D WHERE X eid 2, X work_for R, R creation_date D')
+        self.assertEqual(tree.get_description(), [['work_for', 'work_for_object', 'creation_date']])
         helper.simplify(tree)
@@ -495,8 +498,8 @@
         helper.simplify(tree)
-        # None since const.uid_type is used while solutions have not been computed
-        self.assertEqual(tree.get_description(), [[None, 'work_for', 'creation_date']])
-        
+        # Any since const.uid_type is used while solutions have not been computed
+        self.assertEqual(tree.get_description(), [['Any', 'work_for_object', 'creation_date']])
+
     def test_repr_encoding(self):
         tree = parse(u'Any N where NOT N has_text "bidüle"')
         repr(tree)
 
@@ -499,7 +502,15 @@
     def test_repr_encoding(self):
         tree = parse(u'Any N where NOT N has_text "bidüle"')
         repr(tree)
 
+    def test_get_description_mainvar_objrel(self):
+        tree = sparse('Any X,R,D,Y WHERE X work_for R, R creation_date D, Y owned_by X')
+        self.assertEqual(tree.get_description(0), [['Person', 'work_for', 'creation_date', 'owned_by_object']])
+
+    def test_get_description_mainvar_symrel(self):
+        tree = sparse('Any X,R,D,Y WHERE X work_for R, R creation_date D, Y connait X')
+        self.assertEqual(tree.get_description(0), [['Person, Student', 'work_for', 'creation_date', 'connait']])
+
 
 class GetNodesFunctionTest(TestCase):
     def test_known_values_1(self):
diff --git a/utils.py b/utils.py
index 31cf32b3757a001f42ccf12f194e37351f81dce0_dXRpbHMucHk=..dabf37c4ca94dac430cc34cc0551b0c794028b1d_dXRpbHMucHk= 100644
--- a/utils.py
+++ b/utils.py
@@ -55,10 +55,11 @@
 from logilab.common.adbh import _GenericAdvFuncHelper, FunctionDescr, \
     auto_register_function
 
-def st_description(cls, funcnode):
-    return '%s(%s)' % (cls.name,
-                       ', '.join(child.get_description()
-                                 for child in iter_funcnode_variables(funcnode)))
+def st_description(cls, funcnode, mainindex, tr):
+    return '%s(%s)' % (
+        tr(cls.name),
+        ', '.join(child.get_description(mainindex, tr)
+                  for child in iter_funcnode_variables(funcnode)))
 
 FunctionDescr.st_description = classmethod(st_description)