@wjandrea already explained how to do this; I'll try to explain why the original didn't work. I'll also illustrate an important debugging technique for things like this: if a complex process isn't doing what you want, take it apart and run the pieces individually, and see what they're doing.
In this case, the first iteration the loop works as you expect (it prints "User:art101c40"), so let's not worry about that. Let's look at the second iteration, where i=2. With that value substituted, it runs the command:
echo User:$(tail -n 2 /etc/passwd | cut --delimiter=":" --fields="1")
So, let's run through the pieces and see what they do. First, it runs tail -n 2 /etc/passwd, which will print the last two lines of /etc/passwd. Something vaguely like this:
art101c39:*:10139:99:Art 101 class 39:/home/art101c39:/bin/bash
art101c40:*:10140:99:Art 101 class 40:/home/art101c39:/bin/bash
Note that it prints the last two lines (that's what tail -n 2 does), so it's printing both art101c39 and art101c40. This is the root of the whole problem.
But let's continue tracing its behavior. That output gets piped through cut --delimiter=":" --fields="1", which prints:
art101c39
art101c40
That gets captured by $( ) to be used as arguments to echo. Each of the usernames is on a separate line, so they're separated by a newline, but the $( ) is not in double-quotes so it's subject to word splitting. Word splitting breaks it into "words" based on whitespace (normally spaces, tabs, and newlines), so each username just becomes a separate word. Essentially, it becomes "art101c39" and "art101c40". If either of these had any filename wildcard characters, the shell would then try to turn them into lists of matching files; but there are no wildcard characters, so this doesn't happen. These "words" are then added into the arguments for echo, giving:
echo User:art101c39 art101c40
echo receives two arguments, "User:art101c39" and "art101c40". As it always does, it sticks these together with a space between them and prints the result.
Similar things happen on the third and fourth iterations, with tail printing three and then four accounts, and all of those accounts passing through the rest of the processing.
You could fix this directly by adding head to the pipeline: tail -n $i /etc/passwd | head -n 1 | .... With this, tail will print the last $i lines, and head will eliminate all but the first of these (the $ith from the end of the file). But this approach tends to be inefficient and (IMO) klugy. It involves reading through the entire file to pick out one field from one line. For four lines (accounts), you need to read the entire file four times. If you're going to pick out two fields from each of those users, that'd mean reading the file eight times.
There's usually a simpler and better way to do it, but what that is depends on what the actual goal is. Generally, you'd run tail once, and then common ways to deal with that output include: having awk -F: do all the work; piping to a while IFS=: read -r user pw uid gid fullname homedir shell; do loop; using readarray -t to pull the lines into a shell array where you can work with them directly; etc.
/etc/passwd(less, vi, cat) you'll see that the last 4 lines containart101c37...... Good luck.