Use type parameter when a single type can implement the trait for multiple different types, and the caller chooses which.

trait From<T> {
    fn from(val: T) -> Self; // String can impl From<&str>, From<i32>, etc.
}

Use associated type when there’s exactly one logical “output” type for a given implementation — one impl of the trait = one concrete type. The type is determined by the implementor, not the caller.

trait Iterator {
    type Item; // one impl, one Item type. makes no sense to have Iterator<i32> and Iterator<String> on the same type
    fn next(&mut self) -> Option<Self::Item>;
}

The practical question to ask: “does it make sense for one type to implement this trait more than once with different types?” — yes → type param, no → associated type.