Associations are very different from mere lists of rules. For instance, they are atomic, so Replace cannot dive into them.
The replacement
as //. a_Association :> Keys[a] // Flatten
with does work because one uses //. (a.k.a. ReplaceRepeated): After the first replacement, the outer association was removed and so the next round of replacement can attack the next level. Try ReplaceAll instead and you will see that it stops after the first level:
as /. a_Association :> Keys[a]
The following however works:
ToGraph[a_Association] := Graph[Flatten[{
Map[x \[Function] DirectedEdge["root", x], Keys[a]],
toGraph[a]
}],
VertexLabels -> "Name",
GraphLayout -> "LayeredEmbedding"];
toGraph[a_Association] := {
MapThread[
{key, value} \[Function] If[AssociationQ[value],
{Map[x \[Function] DirectedEdge[key, x], Keys[value]], toGraph[value]},
{DirectedEdge[key, value]}
],
{Keys[a], Values[a]}
]
};
as2 = <|"a" -> <|"c" -> <|"e" -> 2, "f" -> 3|>, "d" -> 4|>, <|"b" -> 5|>|>
ToGraph[as2]

This is a slightly modified version of the code.
SetAttributes[AssociationToGraph, HoldAll];
AssociationToGraph[a_] := Module[{toGraph, data},
toGraph[b_] := {
KeyValueMap[{key, value} \[Function] If[AssociationQ[value],
{
Map[x \[Function] DirectedEdge[key, x], Keys[value]],
toGraph[value]},
{}
],
b]
};
data = Flatten[{Map[
x \[Function] DirectedEdge[ToString[Unevaluated[a]], x], Keys[a]],
toGraph[a]
}];
Graph[data, VertexLabels -> "Name", GraphLayout -> "LayeredEmbedding"]
] /; AssociationQ[a]
as2 = <|"a" -> <|"c" -> <|"e" -> 2, "f" -> 3|>, "d" -> 4|>, <|"b" -> 5|>|>
AssociationToGraph[as2]

Map-pingKeyswould behave the same asQueryat various levels but it's not the case. -- Thanks for the answer. Can you keep the current version but add a modification with (1) only keys, no values; (2) the name of the association instead of generic 'root' ? – alancalvitti Feb 25 '18 at 18:58