DistributeDefinitions is evaluating the definitions, and this only for a large number of definitions

TL;DR;

Execute the following code to fix the problem:

DistributeDefinitions;
DownValues[Parallel`Protected`DistDefs] =
  DownValues[Parallel`Protected`DistDefs] /.
   HoldPattern[
     u : Parallel`Parallel`Private`updates =
      rhs_Language`ExtendedFullDefinition
     ] :>
    (
     u = Replace[
       rhs,
       defs : {(_HoldPattern -> _) ..} :> With[
         {res = RuleDelayed @@@ Unevaluated@defs},
         res /; True
         ],
       {4}
       ]
     );

What does this do?

As mentioned in the comments, the issue is that Language`ExtendedFullDefinition seems to change the return format at 18 down-values. This causes the subsequent manipulations of DistributeDefinitions on the returned Language`DefinitionList[…] expression to leak the evaluation of the definitions (as their r.h.s. are no longer protected by the HoldRest attribute of RuleDelayed).

The code above fixes this by wrapping the call to Language`ExtendedFullDefinition (which happens in Parallel`Protected`DistDefs) with a piece of code that replaces definitions of the form HoldPattern[…]->… with HoldPattern[…]:>…, which prevents the evaluation leak.


When dealing with a larger number of definitions my recommendation is to disable the automatic distribution of definitions with

$DistributedContexts = None

and simply redo the definitions on all parallel kernels:

nI = 20;
(NM[#] := Print[#]) & /@ Range[1, nI];

With[{nI = nI}, ParallelEvaluate[(NM[#] := Print[#])& /@ Range[1, nI];]]

It's faster, too.